summaryrefslogtreecommitdiff
path: root/drivers/tty/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial')
-rw-r--r--drivers/tty/serial/8250/8250.h14
-rw-r--r--drivers/tty/serial/8250/8250_aspeed_vuart.c3
-rw-r--r--drivers/tty/serial/8250/8250_ce4100.c93
-rw-r--r--drivers/tty/serial/8250/8250_core.c324
-rw-r--r--drivers/tty/serial/8250/8250_dw.c36
-rw-r--r--drivers/tty/serial/8250/8250_early.c2
-rw-r--r--drivers/tty/serial/8250/8250_em.c4
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c8
-rw-r--r--drivers/tty/serial/8250/8250_ioc3.c4
-rw-r--r--drivers/tty/serial/8250/8250_lpc18xx.c2
-rw-r--r--drivers/tty/serial/8250/8250_ni.c133
-rw-r--r--drivers/tty/serial/8250/8250_of.c15
-rw-r--r--drivers/tty/serial/8250/8250_omap.c78
-rw-r--r--drivers/tty/serial/8250/8250_pci.c6
-rw-r--r--drivers/tty/serial/8250/8250_pci1xxxx.c10
-rw-r--r--drivers/tty/serial/8250/8250_port.c790
-rw-r--r--drivers/tty/serial/8250/8250_rsa.c98
-rw-r--r--drivers/tty/serial/8250/8250_rt288x.c4
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c4
-rw-r--r--drivers/tty/serial/8250/Kconfig2
-rw-r--r--drivers/tty/serial/8250/Makefile3
-rw-r--r--drivers/tty/serial/Kconfig7
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/altera_uart.c2
-rw-r--r--drivers/tty/serial/amba-pl011.c4
-rw-r--r--drivers/tty/serial/atmel_serial.c4
-rw-r--r--drivers/tty/serial/fsl_lpuart.c15
-rw-r--r--drivers/tty/serial/imx.c19
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c1
-rw-r--r--drivers/tty/serial/lantiq.c4
-rw-r--r--drivers/tty/serial/liteuart.c2
-rw-r--r--drivers/tty/serial/max3100.c5
-rw-r--r--drivers/tty/serial/max310x.c7
-rw-r--r--drivers/tty/serial/milbeaut_usio.c5
-rw-r--r--drivers/tty/serial/pch_uart.c2
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c420
-rw-r--r--drivers/tty/serial/rsci.c480
-rw-r--r--drivers/tty/serial/rsci.h10
-rw-r--r--drivers/tty/serial/sa1100.c2
-rw-r--r--drivers/tty/serial/samsung_tty.c6
-rw-r--r--drivers/tty/serial/sc16is7xx.c7
-rw-r--r--drivers/tty/serial/sccnxp.c2
-rw-r--r--drivers/tty/serial/serial_base_bus.c4
-rw-r--r--drivers/tty/serial/serial_core.c175
-rw-r--r--drivers/tty/serial/sh-sci-common.h175
-rw-r--r--drivers/tty/serial/sh-sci.c853
-rw-r--r--drivers/tty/serial/sh-sci.h2
-rw-r--r--drivers/tty/serial/sifive.c88
-rw-r--r--drivers/tty/serial/tegra-utc.c2
-rw-r--r--drivers/tty/serial/uartlite.c25
50 files changed, 2631 insertions, 1331 deletions
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index b861585ca02a..cfe6ba286b45 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -223,12 +223,6 @@ static inline bool serial8250_clear_THRI(struct uart_8250_port *up)
struct uart_8250_port *serial8250_setup_port(int index);
struct uart_8250_port *serial8250_get_port(int line);
-void serial8250_rpm_get(struct uart_8250_port *p);
-void serial8250_rpm_put(struct uart_8250_port *p);
-
-void serial8250_rpm_get_tx(struct uart_8250_port *p);
-void serial8250_rpm_put_tx(struct uart_8250_port *p);
-
int serial8250_em485_config(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485);
void serial8250_em485_start_tx(struct uart_8250_port *p, bool toggle_ier);
@@ -324,8 +318,16 @@ static inline void serial8250_pnp_exit(void) { }
#ifdef CONFIG_SERIAL_8250_RSA
void univ8250_rsa_support(struct uart_ops *ops);
+void rsa_enable(struct uart_8250_port *up);
+void rsa_disable(struct uart_8250_port *up);
+void rsa_autoconfig(struct uart_8250_port *up);
+void rsa_reset(struct uart_8250_port *up);
#else
static inline void univ8250_rsa_support(struct uart_ops *ops) { }
+static inline void rsa_enable(struct uart_8250_port *up) {}
+static inline void rsa_disable(struct uart_8250_port *up) {}
+static inline void rsa_autoconfig(struct uart_8250_port *up) {}
+static inline void rsa_reset(struct uart_8250_port *up) {}
#endif
#ifdef CONFIG_SERIAL_8250_FINTEK
diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c
index 392447038bfb..26fc0464f1cc 100644
--- a/drivers/tty/serial/8250/8250_aspeed_vuart.c
+++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c
@@ -304,7 +304,8 @@ static void aspeed_vuart_unthrottle(struct uart_port *port)
static void aspeed_vuart_unthrottle_exp(struct timer_list *timer)
{
- struct aspeed_vuart *vuart = from_timer(vuart, timer, unthrottle_timer);
+ struct aspeed_vuart *vuart = timer_container_of(vuart, timer,
+ unthrottle_timer);
struct uart_8250_port *up = vuart->port;
if (!tty_buffer_space_avail(&up->port.state->port)) {
diff --git a/drivers/tty/serial/8250/8250_ce4100.c b/drivers/tty/serial/8250/8250_ce4100.c
new file mode 100644
index 000000000000..81dfb2adbabd
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_ce4100.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel CE4100 platform specific setup code
+ *
+ * (C) Copyright 2010 Intel Corporation
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/types.h>
+
+#include <asm/ce4100.h>
+#include <asm/fixmap.h>
+#include <asm/page.h>
+
+#include <linux/serial_reg.h>
+#include <linux/serial_8250.h>
+
+static unsigned int mem_serial_in(struct uart_port *p, int offset)
+{
+ offset = offset << p->regshift;
+ return readl(p->membase + offset);
+}
+
+/*
+ * The UART Tx interrupts are not set under some conditions and therefore serial
+ * transmission hangs. This is a silicon issue and has not been root caused. The
+ * workaround for this silicon issue checks UART_LSR_THRE bit and UART_LSR_TEMT
+ * bit of LSR register in interrupt handler to see whether at least one of these
+ * two bits is set, if so then process the transmit request. If this workaround
+ * is not applied, then the serial transmission may hang. This workaround is for
+ * errata number 9 in Errata - B step.
+*/
+static u32 ce4100_mem_serial_in(struct uart_port *p, unsigned int offset)
+{
+ u32 ret, ier, lsr;
+
+ ret = mem_serial_in(p, offset);
+ if (offset != UART_IIR || !(ret & UART_IIR_NO_INT))
+ return ret;
+
+ /* see if the TX interrupt should have really set */
+ ier = mem_serial_in(p, UART_IER);
+ /* see if the UART's XMIT interrupt is enabled */
+ if (!(ier & UART_IER_THRI))
+ return ret;
+
+ lsr = mem_serial_in(p, UART_LSR);
+ /* now check to see if the UART should be generating an interrupt (but isn't) */
+ if (lsr & (UART_LSR_THRE | UART_LSR_TEMT))
+ ret &= ~UART_IIR_NO_INT;
+
+ return ret;
+}
+
+static void ce4100_mem_serial_out(struct uart_port *p, unsigned int offset, u32 value)
+{
+ offset <<= p->regshift;
+ writel(value, p->membase + offset);
+}
+
+static void ce4100_serial_fixup(int port, struct uart_port *up, u32 *capabilities)
+{
+#ifdef CONFIG_EARLY_PRINTK
+ /*
+ * Override the legacy port configuration that comes from
+ * asm/serial.h. Using the ioport driver then switching to the
+ * PCI memmaped driver hangs the IOAPIC.
+ */
+ if (up->iotype != UPIO_MEM32) {
+ up->uartclk = 14745600;
+ up->mapbase = 0xdffe0200;
+ set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, up->mapbase & PAGE_MASK);
+ up->membase = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
+ up->membase += up->mapbase & ~PAGE_MASK;
+ up->mapbase += port * 0x100;
+ up->membase += port * 0x100;
+ up->iotype = UPIO_MEM32;
+ up->regshift = 2;
+ up->irq = 4;
+ }
+#endif
+ up->iobase = 0;
+ up->serial_in = ce4100_mem_serial_in;
+ up->serial_out = ce4100_mem_serial_out;
+
+ *capabilities |= (1 << 12);
+}
+
+void __init sdv_serial_fixup(void)
+{
+ serial8250_set_isa_configurator(ce4100_serial_fixup);
+}
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 5a56f853cf6d..feb920c5b2e8 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -13,6 +13,7 @@
*/
#include <linux/acpi.h>
+#include <linux/hashtable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
@@ -47,8 +48,8 @@ struct irq_info {
struct list_head *head;
};
-#define NR_IRQ_HASH 32 /* Can be adjusted later */
-static struct hlist_head irq_lists[NR_IRQ_HASH];
+#define IRQ_HASH_BITS 5 /* Can be adjusted later */
+static DEFINE_HASHTABLE(irq_lists, IRQ_HASH_BITS);
static DEFINE_MUTEX(hash_mutex); /* Used to walk the hash */
/*
@@ -71,17 +72,12 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
struct list_head *l, *end = NULL;
int pass_counter = 0, handled = 0;
- pr_debug("%s(%d): start\n", __func__, irq);
-
spin_lock(&i->lock);
l = i->head;
do {
- struct uart_8250_port *up;
- struct uart_port *port;
-
- up = list_entry(l, struct uart_8250_port, list);
- port = &up->port;
+ struct uart_8250_port *up = list_entry(l, struct uart_8250_port, list);
+ struct uart_port *port = &up->port;
if (port->handle_irq(port)) {
handled = 1;
@@ -97,8 +93,6 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
spin_unlock(&i->lock);
- pr_debug("%s(%d): end\n", __func__, irq);
-
return IRQ_RETVAL(handled);
}
@@ -129,32 +123,44 @@ static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
}
}
-static int serial_link_irq_chain(struct uart_8250_port *up)
+/*
+ * Either:
+ * - find the corresponding info in the hashtable and return it, or
+ * - allocate a new one, add it to the hashtable and return it.
+ */
+static struct irq_info *serial_get_or_create_irq_info(const struct uart_8250_port *up)
{
- struct hlist_head *h;
struct irq_info *i;
- int ret;
mutex_lock(&hash_mutex);
- h = &irq_lists[up->port.irq % NR_IRQ_HASH];
-
- hlist_for_each_entry(i, h, node)
+ hash_for_each_possible(irq_lists, i, node, up->port.irq)
if (i->irq == up->port.irq)
- break;
+ goto unlock;
+ i = kzalloc(sizeof(*i), GFP_KERNEL);
if (i == NULL) {
- i = kzalloc(sizeof(struct irq_info), GFP_KERNEL);
- if (i == NULL) {
- mutex_unlock(&hash_mutex);
- return -ENOMEM;
- }
- spin_lock_init(&i->lock);
- i->irq = up->port.irq;
- hlist_add_head(&i->node, h);
+ i = ERR_PTR(-ENOMEM);
+ goto unlock;
}
+ spin_lock_init(&i->lock);
+ i->irq = up->port.irq;
+ hash_add(irq_lists, &i->node, i->irq);
+unlock:
mutex_unlock(&hash_mutex);
+ return i;
+}
+
+static int serial_link_irq_chain(struct uart_8250_port *up)
+{
+ struct irq_info *i;
+ int ret;
+
+ i = serial_get_or_create_irq_info(up);
+ if (IS_ERR(i))
+ return PTR_ERR(i);
+
spin_lock_irq(&i->lock);
if (i->head) {
@@ -178,13 +184,10 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
static void serial_unlink_irq_chain(struct uart_8250_port *up)
{
struct irq_info *i;
- struct hlist_head *h;
mutex_lock(&hash_mutex);
- h = &irq_lists[up->port.irq % NR_IRQ_HASH];
-
- hlist_for_each_entry(i, h, node)
+ hash_for_each_possible(irq_lists, i, node, up->port.irq)
if (i->irq == up->port.irq)
break;
@@ -206,7 +209,7 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up)
*/
static void serial8250_timeout(struct timer_list *t)
{
- struct uart_8250_port *up = from_timer(up, t, timer);
+ struct uart_8250_port *up = timer_container_of(up, t, timer);
up->port.handle_irq(&up->port);
mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port));
@@ -214,7 +217,7 @@ static void serial8250_timeout(struct timer_list *t)
static void serial8250_backup_timeout(struct timer_list *t)
{
- struct uart_8250_port *up = from_timer(up, t, timer);
+ struct uart_8250_port *up = timer_container_of(up, t, timer);
unsigned int iir, ier = 0, lsr;
unsigned long flags;
@@ -461,7 +464,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
char *options)
{
char match[] = "uart"; /* 8250-specific earlycon name */
- unsigned char iotype;
+ enum uart_iotype iotype;
resource_size_t addr;
int i;
@@ -714,139 +717,142 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
nr_uarts++;
}
- if (uart->port.type != PORT_8250_CIR) {
- struct mctrl_gpios *gpios;
-
- if (uart->port.dev)
- uart_remove_one_port(&serial8250_reg, &uart->port);
-
- uart->port.ctrl_id = up->port.ctrl_id;
- uart->port.port_id = up->port.port_id;
- uart->port.iobase = up->port.iobase;
- uart->port.membase = up->port.membase;
- uart->port.irq = up->port.irq;
- uart->port.irqflags = up->port.irqflags;
- uart->port.uartclk = up->port.uartclk;
- uart->port.fifosize = up->port.fifosize;
- uart->port.regshift = up->port.regshift;
- uart->port.iotype = up->port.iotype;
- uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
- uart->bugs = up->bugs;
- uart->port.mapbase = up->port.mapbase;
- uart->port.mapsize = up->port.mapsize;
- uart->port.private_data = up->port.private_data;
- uart->tx_loadsz = up->tx_loadsz;
- uart->capabilities = up->capabilities;
- uart->port.throttle = up->port.throttle;
- uart->port.unthrottle = up->port.unthrottle;
- uart->port.rs485_config = up->port.rs485_config;
- uart->port.rs485_supported = up->port.rs485_supported;
- uart->port.rs485 = up->port.rs485;
- uart->rs485_start_tx = up->rs485_start_tx;
- uart->rs485_stop_tx = up->rs485_stop_tx;
- uart->lsr_save_mask = up->lsr_save_mask;
- uart->dma = up->dma;
-
- /* Take tx_loadsz from fifosize if it wasn't set separately */
- if (uart->port.fifosize && !uart->tx_loadsz)
- uart->tx_loadsz = uart->port.fifosize;
-
- if (up->port.dev) {
- uart->port.dev = up->port.dev;
- ret = uart_get_rs485_mode(&uart->port);
- if (ret)
- goto err;
- }
+ /* Check if it is CIR already. We check this below again, see there why. */
+ if (uart->port.type == PORT_8250_CIR) {
+ ret = -ENODEV;
+ goto unlock;
+ }
- if (up->port.flags & UPF_FIXED_TYPE)
- uart->port.type = up->port.type;
+ if (uart->port.dev)
+ uart_remove_one_port(&serial8250_reg, &uart->port);
+
+ uart->port.ctrl_id = up->port.ctrl_id;
+ uart->port.port_id = up->port.port_id;
+ uart->port.iobase = up->port.iobase;
+ uart->port.membase = up->port.membase;
+ uart->port.irq = up->port.irq;
+ uart->port.irqflags = up->port.irqflags;
+ uart->port.uartclk = up->port.uartclk;
+ uart->port.fifosize = up->port.fifosize;
+ uart->port.regshift = up->port.regshift;
+ uart->port.iotype = up->port.iotype;
+ uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
+ uart->bugs = up->bugs;
+ uart->port.mapbase = up->port.mapbase;
+ uart->port.mapsize = up->port.mapsize;
+ uart->port.private_data = up->port.private_data;
+ uart->tx_loadsz = up->tx_loadsz;
+ uart->capabilities = up->capabilities;
+ uart->port.throttle = up->port.throttle;
+ uart->port.unthrottle = up->port.unthrottle;
+ uart->port.rs485_config = up->port.rs485_config;
+ uart->port.rs485_supported = up->port.rs485_supported;
+ uart->port.rs485 = up->port.rs485;
+ uart->rs485_start_tx = up->rs485_start_tx;
+ uart->rs485_stop_tx = up->rs485_stop_tx;
+ uart->lsr_save_mask = up->lsr_save_mask;
+ uart->dma = up->dma;
+
+ /* Take tx_loadsz from fifosize if it wasn't set separately */
+ if (uart->port.fifosize && !uart->tx_loadsz)
+ uart->tx_loadsz = uart->port.fifosize;
+
+ if (up->port.dev) {
+ uart->port.dev = up->port.dev;
+ ret = uart_get_rs485_mode(&uart->port);
+ if (ret)
+ goto err;
+ }
- /*
- * Only call mctrl_gpio_init(), if the device has no ACPI
- * companion device
- */
- if (!has_acpi_companion(uart->port.dev)) {
- gpios = mctrl_gpio_init(&uart->port, 0);
- if (IS_ERR(gpios)) {
- ret = PTR_ERR(gpios);
- goto err;
- } else {
- uart->gpios = gpios;
- }
- }
+ if (up->port.flags & UPF_FIXED_TYPE)
+ uart->port.type = up->port.type;
- serial8250_set_defaults(uart);
-
- /* Possibly override default I/O functions. */
- if (up->port.serial_in)
- uart->port.serial_in = up->port.serial_in;
- if (up->port.serial_out)
- uart->port.serial_out = up->port.serial_out;
- if (up->port.handle_irq)
- uart->port.handle_irq = up->port.handle_irq;
- /* Possibly override set_termios call */
- if (up->port.set_termios)
- uart->port.set_termios = up->port.set_termios;
- if (up->port.set_ldisc)
- uart->port.set_ldisc = up->port.set_ldisc;
- if (up->port.get_mctrl)
- uart->port.get_mctrl = up->port.get_mctrl;
- if (up->port.set_mctrl)
- uart->port.set_mctrl = up->port.set_mctrl;
- if (up->port.get_divisor)
- uart->port.get_divisor = up->port.get_divisor;
- if (up->port.set_divisor)
- uart->port.set_divisor = up->port.set_divisor;
- if (up->port.startup)
- uart->port.startup = up->port.startup;
- if (up->port.shutdown)
- uart->port.shutdown = up->port.shutdown;
- if (up->port.pm)
- uart->port.pm = up->port.pm;
- if (up->port.handle_break)
- uart->port.handle_break = up->port.handle_break;
- if (up->dl_read)
- uart->dl_read = up->dl_read;
- if (up->dl_write)
- uart->dl_write = up->dl_write;
-
- if (uart->port.type != PORT_8250_CIR) {
- if (uart_console_registered(&uart->port))
- pm_runtime_get_sync(uart->port.dev);
-
- if (serial8250_isa_config != NULL)
- serial8250_isa_config(0, &uart->port,
- &uart->capabilities);
-
- serial8250_apply_quirks(uart);
- ret = uart_add_one_port(&serial8250_reg,
- &uart->port);
- if (ret)
- goto err;
-
- ret = uart->port.line;
+ /*
+ * Only call mctrl_gpio_init(), if the device has no ACPI
+ * companion device
+ */
+ if (!has_acpi_companion(uart->port.dev)) {
+ struct mctrl_gpios *gpios = mctrl_gpio_init(&uart->port, 0);
+ if (IS_ERR(gpios)) {
+ ret = PTR_ERR(gpios);
+ goto err;
} else {
- dev_info(uart->port.dev,
- "skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
- uart->port.iobase,
- (unsigned long long)uart->port.mapbase,
- uart->port.irq);
-
- ret = 0;
+ uart->gpios = gpios;
}
+ }
- if (!uart->lsr_save_mask)
- uart->lsr_save_mask = LSR_SAVE_FLAGS; /* Use default LSR mask */
+ serial8250_set_defaults(uart);
+
+ /* Possibly override default I/O functions. */
+ if (up->port.serial_in)
+ uart->port.serial_in = up->port.serial_in;
+ if (up->port.serial_out)
+ uart->port.serial_out = up->port.serial_out;
+ if (up->port.handle_irq)
+ uart->port.handle_irq = up->port.handle_irq;
+ /* Possibly override set_termios call */
+ if (up->port.set_termios)
+ uart->port.set_termios = up->port.set_termios;
+ if (up->port.set_ldisc)
+ uart->port.set_ldisc = up->port.set_ldisc;
+ if (up->port.get_mctrl)
+ uart->port.get_mctrl = up->port.get_mctrl;
+ if (up->port.set_mctrl)
+ uart->port.set_mctrl = up->port.set_mctrl;
+ if (up->port.get_divisor)
+ uart->port.get_divisor = up->port.get_divisor;
+ if (up->port.set_divisor)
+ uart->port.set_divisor = up->port.set_divisor;
+ if (up->port.startup)
+ uart->port.startup = up->port.startup;
+ if (up->port.shutdown)
+ uart->port.shutdown = up->port.shutdown;
+ if (up->port.pm)
+ uart->port.pm = up->port.pm;
+ if (up->port.handle_break)
+ uart->port.handle_break = up->port.handle_break;
+ if (up->dl_read)
+ uart->dl_read = up->dl_read;
+ if (up->dl_write)
+ uart->dl_write = up->dl_write;
+
+ /* Check the type (again)! It might have changed by the port.type assignment above. */
+ if (uart->port.type != PORT_8250_CIR) {
+ if (uart_console_registered(&uart->port))
+ pm_runtime_get_sync(uart->port.dev);
- /* Initialise interrupt backoff work if required */
- if (up->overrun_backoff_time_ms > 0) {
- uart->overrun_backoff_time_ms =
- up->overrun_backoff_time_ms;
- INIT_DELAYED_WORK(&uart->overrun_backoff,
- serial_8250_overrun_backoff_work);
- } else {
- uart->overrun_backoff_time_ms = 0;
- }
+ if (serial8250_isa_config != NULL)
+ serial8250_isa_config(0, &uart->port,
+ &uart->capabilities);
+
+ serial8250_apply_quirks(uart);
+ ret = uart_add_one_port(&serial8250_reg,
+ &uart->port);
+ if (ret)
+ goto err;
+
+ ret = uart->port.line;
+ } else {
+ dev_info(uart->port.dev,
+ "skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
+ uart->port.iobase,
+ (unsigned long long)uart->port.mapbase,
+ uart->port.irq);
+
+ ret = 0;
+ }
+
+ if (!uart->lsr_save_mask)
+ uart->lsr_save_mask = LSR_SAVE_FLAGS; /* Use default LSR mask */
+
+ /* Initialise interrupt backoff work if required */
+ if (up->overrun_backoff_time_ms > 0) {
+ uart->overrun_backoff_time_ms =
+ up->overrun_backoff_time_ms;
+ INIT_DELAYED_WORK(&uart->overrun_backoff,
+ serial_8250_overrun_backoff_work);
+ } else {
+ uart->overrun_backoff_time_ms = 0;
}
unlock:
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 1902f29444a1..a53ba04d9770 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -67,8 +67,8 @@ struct dw8250_data {
struct dw8250_port_data data;
const struct dw8250_platform_data *pdata;
- int msr_mask_on;
- int msr_mask_off;
+ u32 msr_mask_on;
+ u32 msr_mask_off;
struct clk *clk;
struct clk *pclk;
struct notifier_block clk_notifier;
@@ -94,7 +94,7 @@ static inline struct dw8250_data *work_to_dw8250_data(struct work_struct *work)
return container_of(work, struct dw8250_data, clk_work);
}
-static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
+static inline u32 dw8250_modify_msr(struct uart_port *p, unsigned int offset, u32 value)
{
struct dw8250_data *d = to_dw8250_data(p->private_data);
@@ -145,7 +145,7 @@ static void dw8250_force_idle(struct uart_port *p)
* routine. Hence, it must not call serial_port_out() or serial_out()
* against the modified registers here, i.e. LCR.
*/
-static void dw8250_check_lcr(struct uart_port *p, int offset, int value)
+static void dw8250_check_lcr(struct uart_port *p, unsigned int offset, u32 value)
{
struct dw8250_data *d = to_dw8250_data(p->private_data);
void __iomem *addr = p->membase + (offset << p->regshift);
@@ -156,7 +156,7 @@ static void dw8250_check_lcr(struct uart_port *p, int offset, int value)
/* Make sure LCR write wasn't ignored */
while (tries--) {
- unsigned int lcr = serial_port_in(p, offset);
+ u32 lcr = serial_port_in(p, offset);
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
return;
@@ -205,13 +205,13 @@ static void dw8250_tx_wait_empty(struct uart_port *p)
}
}
-static void dw8250_serial_out(struct uart_port *p, int offset, int value)
+static void dw8250_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
writeb(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
-static void dw8250_serial_out38x(struct uart_port *p, int offset, int value)
+static void dw8250_serial_out38x(struct uart_port *p, unsigned int offset, u32 value)
{
/* Allow the TX to drain before we reconfigure */
if (offset == UART_LCR)
@@ -220,22 +220,22 @@ static void dw8250_serial_out38x(struct uart_port *p, int offset, int value)
dw8250_serial_out(p, offset, value);
}
-static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
+static u32 dw8250_serial_in(struct uart_port *p, unsigned int offset)
{
- unsigned int value = readb(p->membase + (offset << p->regshift));
+ u32 value = readb(p->membase + (offset << p->regshift));
return dw8250_modify_msr(p, offset, value);
}
#ifdef CONFIG_64BIT
-static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
+static u32 dw8250_serial_inq(struct uart_port *p, unsigned int offset)
{
u8 value = __raw_readq(p->membase + (offset << p->regshift));
return dw8250_modify_msr(p, offset, value);
}
-static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
+static void dw8250_serial_outq(struct uart_port *p, unsigned int offset, u32 value)
{
value &= 0xff;
__raw_writeq(value, p->membase + (offset << p->regshift));
@@ -246,28 +246,28 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
}
#endif /* CONFIG_64BIT */
-static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
+static void dw8250_serial_out32(struct uart_port *p, unsigned int offset, u32 value)
{
writel(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
-static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
+static u32 dw8250_serial_in32(struct uart_port *p, unsigned int offset)
{
- unsigned int value = readl(p->membase + (offset << p->regshift));
+ u32 value = readl(p->membase + (offset << p->regshift));
return dw8250_modify_msr(p, offset, value);
}
-static void dw8250_serial_out32be(struct uart_port *p, int offset, int value)
+static void dw8250_serial_out32be(struct uart_port *p, unsigned int offset, u32 value)
{
iowrite32be(value, p->membase + (offset << p->regshift));
dw8250_check_lcr(p, offset, value);
}
-static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset)
+static u32 dw8250_serial_in32be(struct uart_port *p, unsigned int offset)
{
- unsigned int value = ioread32be(p->membase + (offset << p->regshift));
+ u32 value = ioread32be(p->membase + (offset << p->regshift));
return dw8250_modify_msr(p, offset, value);
}
@@ -392,7 +392,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
rate = clk_round_rate(d->clk, newrate);
if (rate > 0) {
/*
- * Note that any clock-notifer worker will block in
+ * Note that any clock-notifier worker will block in
* serial8250_update_uartclk() until we are done.
*/
ret = clk_set_rate(d->clk, newrate);
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 842422921765..dc0371857ecb 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -77,6 +77,8 @@ static void serial8250_early_out(struct uart_port *port, int offset, int value)
outb(value, port->iobase + offset);
break;
#endif
+ default:
+ break;
}
}
diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c
index 35094f884492..e90c71494944 100644
--- a/drivers/tty/serial/8250/8250_em.c
+++ b/drivers/tty/serial/8250/8250_em.c
@@ -59,7 +59,7 @@ static void serial8250_em_serial_out_helper(struct uart_port *p, int offset,
}
}
-static unsigned int serial8250_em_serial_in(struct uart_port *p, int offset)
+static u32 serial8250_em_serial_in(struct uart_port *p, unsigned int offset)
{
switch (offset) {
case UART_RX: /* RX @ 0x00 */
@@ -119,7 +119,7 @@ static void serial8250_em_reg_update(struct uart_port *p, int off, int value)
serial8250_em_serial_out_helper(p, UART_HCR0_EM, hcr0);
}
-static void serial8250_em_serial_out(struct uart_port *p, int offset, int value)
+static void serial8250_em_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
switch (offset) {
case UART_TX:
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index a73dd3773640..94542fc143c2 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -168,9 +168,9 @@ OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart",
OF_EARLYCON_DECLARE(x1000_uart, "ingenic,x1000-uart",
ingenic_early_console_setup);
-static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
+static void ingenic_uart_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
- int ier;
+ u32 ier;
switch (offset) {
case UART_FCR:
@@ -206,9 +206,9 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
writeb(value, p->membase + (offset << p->regshift));
}
-static unsigned int ingenic_uart_serial_in(struct uart_port *p, int offset)
+static u32 ingenic_uart_serial_in(struct uart_port *p, unsigned int offset)
{
- unsigned int value;
+ u8 value;
value = readb(p->membase + (offset << p->regshift));
diff --git a/drivers/tty/serial/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c
index 499e80aa4cf9..3ebda9a5d07d 100644
--- a/drivers/tty/serial/8250/8250_ioc3.c
+++ b/drivers/tty/serial/8250/8250_ioc3.c
@@ -21,12 +21,12 @@ struct ioc3_8250_data {
int line;
};
-static unsigned int ioc3_serial_in(struct uart_port *p, int offset)
+static u32 ioc3_serial_in(struct uart_port *p, unsigned int offset)
{
return readb(p->membase + (offset ^ 3));
}
-static void ioc3_serial_out(struct uart_port *p, int offset, int value)
+static void ioc3_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
writeb(value, p->membase + (offset ^ 3));
}
diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c
index d52445948da0..6c0489c9c253 100644
--- a/drivers/tty/serial/8250/8250_lpc18xx.c
+++ b/drivers/tty/serial/8250/8250_lpc18xx.c
@@ -67,7 +67,7 @@ static int lpc18xx_rs485_config(struct uart_port *port, struct ktermios *termios
return 0;
}
-static void lpc18xx_uart_serial_out(struct uart_port *p, int offset, int value)
+static void lpc18xx_uart_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
/*
* For DMA mode one must ensure that the UART_FCR_DMA_SELECT
diff --git a/drivers/tty/serial/8250/8250_ni.c b/drivers/tty/serial/8250/8250_ni.c
index b10a42d2ad63..cb5b42b3609c 100644
--- a/drivers/tty/serial/8250/8250_ni.c
+++ b/drivers/tty/serial/8250/8250_ni.c
@@ -10,14 +10,18 @@
* Copyright 2012-2023 National Instruments Corporation
*/
-#include <linux/acpi.h>
#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/init.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/property.h>
-#include <linux/clk.h>
+#include <linux/serial_core.h>
+#include <linux/types.h>
#include "8250.h"
@@ -90,10 +94,10 @@ static int ni16550_disable_transceivers(struct uart_port *port)
{
u8 pcr;
- pcr = port->serial_in(port, NI16550_PCR_OFFSET);
+ pcr = serial_port_in(port, NI16550_PCR_OFFSET);
pcr &= ~NI16550_PCR_TXVR_ENABLE_BIT;
dev_dbg(port->dev, "disable transceivers: write pcr: 0x%02x\n", pcr);
- port->serial_out(port, NI16550_PCR_OFFSET, pcr);
+ serial_port_out(port, NI16550_PCR_OFFSET, pcr);
return 0;
}
@@ -105,7 +109,7 @@ static int ni16550_rs485_config(struct uart_port *port,
struct uart_8250_port *up = container_of(port, struct uart_8250_port, port);
u8 pcr;
- pcr = serial_in(up, NI16550_PCR_OFFSET);
+ pcr = serial_port_in(port, NI16550_PCR_OFFSET);
pcr &= ~NI16550_PCR_WIRE_MODE_MASK;
if ((rs485->flags & SER_RS485_MODE_RS422) ||
@@ -120,7 +124,7 @@ static int ni16550_rs485_config(struct uart_port *port,
}
dev_dbg(port->dev, "config rs485: write pcr: 0x%02x, acr: %02x\n", pcr, up->acr);
- serial_out(up, NI16550_PCR_OFFSET, pcr);
+ serial_port_out(port, NI16550_PCR_OFFSET, pcr);
serial_icr_write(up, UART_ACR, up->acr);
return 0;
@@ -224,31 +228,26 @@ static int ni16550_get_regs(struct platform_device *pdev,
{
struct resource *regs;
- regs = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (regs) {
+ regs = platform_get_mem_or_io(pdev, 0);
+ if (!regs)
+ return dev_err_probe(&pdev->dev, -EINVAL, "no registers defined\n");
+
+ switch (resource_type(regs)) {
+ case IORESOURCE_IO:
port->iotype = UPIO_PORT;
port->iobase = regs->start;
return 0;
- }
-
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (regs) {
+ case IORESOURCE_MEM:
port->iotype = UPIO_MEM;
port->mapbase = regs->start;
port->mapsize = resource_size(regs);
port->flags |= UPF_IOREMAP;
- port->membase = devm_ioremap(&pdev->dev, port->mapbase,
- port->mapsize);
- if (!port->membase)
- return -ENOMEM;
-
return 0;
+ default:
+ return -EINVAL;
}
-
- dev_err(&pdev->dev, "no registers defined\n");
- return -EINVAL;
}
/*
@@ -276,86 +275,80 @@ static void ni16550_set_mctrl(struct uart_port *port, unsigned int mctrl)
static int ni16550_probe(struct platform_device *pdev)
{
+ struct uart_8250_port *uart __free(kfree) = NULL;
const struct ni16550_device_info *info;
struct device *dev = &pdev->dev;
- struct uart_8250_port uart = {};
unsigned int txfifosz, rxfifosz;
- unsigned int prescaler = 0;
struct ni16550_data *data;
+ unsigned int prescaler;
const char *portmode;
bool rs232_property;
int ret;
- int irq;
+
+ uart = kzalloc(sizeof(*uart), GFP_KERNEL);
+ if (!uart)
+ return -ENOMEM;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- spin_lock_init(&uart.port.lock);
+ spin_lock_init(&uart->port.lock);
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- ret = ni16550_get_regs(pdev, &uart.port);
+ ret = ni16550_get_regs(pdev, &uart->port);
if (ret < 0)
return ret;
/* early setup so that serial_in()/serial_out() work */
- serial8250_set_defaults(&uart);
+ serial8250_set_defaults(uart);
info = device_get_match_data(dev);
- uart.port.dev = dev;
- uart.port.irq = irq;
- uart.port.irqflags = IRQF_SHARED;
- uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
- | UPF_FIXED_PORT | UPF_FIXED_TYPE;
- uart.port.startup = ni16550_port_startup;
- uart.port.shutdown = ni16550_port_shutdown;
+ uart->port.dev = dev;
+ uart->port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ uart->port.startup = ni16550_port_startup;
+ uart->port.shutdown = ni16550_port_shutdown;
/*
* Hardware instantiation of FIFO sizes are held in registers.
*/
- txfifosz = ni16550_read_fifo_size(&uart, NI16550_TFS_OFFSET);
- rxfifosz = ni16550_read_fifo_size(&uart, NI16550_RFS_OFFSET);
+ txfifosz = ni16550_read_fifo_size(uart, NI16550_TFS_OFFSET);
+ rxfifosz = ni16550_read_fifo_size(uart, NI16550_RFS_OFFSET);
dev_dbg(dev, "NI 16550 has TX FIFO size %u, RX FIFO size %u\n",
txfifosz, rxfifosz);
- uart.port.type = PORT_16550A;
- uart.port.fifosize = txfifosz;
- uart.tx_loadsz = txfifosz;
- uart.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
- uart.capabilities = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR;
+ uart->port.type = PORT_16550A;
+ uart->port.fifosize = txfifosz;
+ uart->tx_loadsz = txfifosz;
+ uart->fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
+ uart->capabilities = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR;
/*
* Declaration of the base clock frequency can come from one of:
* - static declaration in this driver (for older ACPI IDs)
- * - a "clock-frquency" ACPI
+ * - a "clock-frequency" ACPI
*/
- if (info->uartclk)
- uart.port.uartclk = info->uartclk;
- if (device_property_read_u32(dev, "clock-frequency",
- &uart.port.uartclk)) {
+ uart->port.uartclk = info->uartclk;
+
+ ret = uart_read_port_properties(&uart->port);
+ if (ret)
+ return ret;
+
+ if (!uart->port.uartclk) {
data->clk = devm_clk_get_enabled(dev, NULL);
if (!IS_ERR(data->clk))
- uart.port.uartclk = clk_get_rate(data->clk);
+ uart->port.uartclk = clk_get_rate(data->clk);
}
- if (!uart.port.uartclk) {
- dev_err(dev, "unable to determine clock frequency!\n");
- ret = -ENODEV;
- goto err;
- }
+ if (!uart->port.uartclk)
+ return dev_err_probe(dev, -ENODEV, "unable to determine clock frequency!\n");
- if (info->prescaler)
- prescaler = info->prescaler;
+ prescaler = info->prescaler;
device_property_read_u32(dev, "clock-prescaler", &prescaler);
-
- if (prescaler != 0) {
- uart.port.set_mctrl = ni16550_set_mctrl;
- ni16550_config_prescaler(&uart, (u8)prescaler);
+ if (prescaler) {
+ uart->port.set_mctrl = ni16550_set_mctrl;
+ ni16550_config_prescaler(uart, (u8)prescaler);
}
/*
@@ -373,7 +366,7 @@ static int ni16550_probe(struct platform_device *pdev)
dev_dbg(dev, "port is in %s mode (via device property)\n",
rs232_property ? "RS-232" : "RS-485");
} else if (info->flags & NI_HAS_PMR) {
- rs232_property = is_pmr_rs232_mode(&uart);
+ rs232_property = is_pmr_rs232_mode(uart);
dev_dbg(dev, "port is in %s mode (via PMR)\n",
rs232_property ? "RS-232" : "RS-485");
@@ -388,19 +381,16 @@ static int ni16550_probe(struct platform_device *pdev)
* Neither the 'transceiver' property nor the PMR indicate
* that this is an RS-232 port, so it must be an RS-485 one.
*/
- ni16550_rs485_setup(&uart.port);
+ ni16550_rs485_setup(&uart->port);
}
- ret = serial8250_register_8250_port(&uart);
+ ret = serial8250_register_8250_port(uart);
if (ret < 0)
- goto err;
+ return ret;
data->line = ret;
platform_set_drvdata(pdev, data);
return 0;
-
-err:
- return ret;
}
static void ni16550_remove(struct platform_device *pdev)
@@ -410,7 +400,6 @@ static void ni16550_remove(struct platform_device *pdev)
serial8250_unregister_port(data->line);
}
-#ifdef CONFIG_ACPI
/* NI 16550 RS-485 Interface */
static const struct ni16550_device_info nic7750 = {
.uartclk = 33333333,
@@ -435,20 +424,20 @@ static const struct ni16550_device_info nic7a69 = {
.uartclk = 29629629,
.prescaler = 0x09,
};
+
static const struct acpi_device_id ni16550_acpi_match[] = {
{ "NIC7750", (kernel_ulong_t)&nic7750 },
{ "NIC7772", (kernel_ulong_t)&nic7772 },
{ "NIC792B", (kernel_ulong_t)&nic792b },
{ "NIC7A69", (kernel_ulong_t)&nic7a69 },
- { },
+ { }
};
MODULE_DEVICE_TABLE(acpi, ni16550_acpi_match);
-#endif
static struct platform_driver ni16550_driver = {
.driver = {
.name = "ni16550",
- .acpi_match_table = ACPI_PTR(ni16550_acpi_match),
+ .acpi_match_table = ni16550_acpi_match,
},
.probe = ni16550_probe,
.remove = ni16550_remove,
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 11c860ea80f6..d178b6c54ea1 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -24,6 +24,7 @@
struct of_serial_info {
struct clk *clk;
+ struct clk *bus_clk;
struct reset_control *rst;
int type;
int line;
@@ -123,12 +124,22 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
/* Get clk rate through clk driver if present */
if (!port->uartclk) {
- info->clk = devm_clk_get_enabled(dev, NULL);
+ struct clk *bus_clk;
+
+ bus_clk = devm_clk_get_optional_enabled(dev, "bus");
+ if (IS_ERR(bus_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(bus_clk), "failed to get bus clock\n");
+ goto err_pmruntime;
+ }
+
+ /* If the bus clock is required, core clock must be named */
+ info->clk = devm_clk_get_enabled(dev, bus_clk ? "core" : NULL);
if (IS_ERR(info->clk)) {
ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n");
goto err_pmruntime;
}
+ info->bus_clk = bus_clk;
port->uartclk = clk_get_rate(info->clk);
}
/* If current-speed was set, then try not to change it. */
@@ -290,6 +301,7 @@ static int of_serial_suspend(struct device *dev)
if (!uart_console(port) || console_suspend_enabled) {
pm_runtime_put_sync(dev);
clk_disable_unprepare(info->clk);
+ clk_disable_unprepare(info->bus_clk);
}
return 0;
}
@@ -302,6 +314,7 @@ static int of_serial_resume(struct device *dev)
if (!uart_console(port) || console_suspend_enabled) {
pm_runtime_get_sync(dev);
+ clk_prepare_enable(info->bus_clk);
clk_prepare_enable(info->clk);
}
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 2a0ce11f405d..6707f55bdbe7 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -176,7 +176,7 @@ static u32 uart_read(struct omap8250_priv *priv, u32 reg)
static void __omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_8250_port *up = up_to_u8250p(port);
- struct omap8250_priv *priv = up->port.private_data;
+ struct omap8250_priv *priv = port->private_data;
u8 lcr;
serial8250_do_set_mctrl(port, mctrl);
@@ -303,12 +303,13 @@ static void omap8250_update_mdr1(struct uart_8250_port *up,
static void omap8250_restore_regs(struct uart_8250_port *up)
{
- struct omap8250_priv *priv = up->port.private_data;
+ struct uart_port *port = &up->port;
+ struct omap8250_priv *priv = port->private_data;
struct uart_8250_dma *dma = up->dma;
u8 mcr = serial8250_in_MCR(up);
/* Port locked to synchronize UART_IER access against the console. */
- lockdep_assert_held_once(&up->port.lock);
+ lockdep_assert_held_once(&port->lock);
if (dma && dma->tx_running) {
/*
@@ -359,12 +360,12 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
omap8250_update_mdr1(up, priv);
- __omap8250_set_mctrl(&up->port, up->port.mctrl);
+ __omap8250_set_mctrl(port, port->mctrl);
serial_out(up, UART_OMAP_MDR3, priv->mdr3);
- if (up->port.rs485.flags & SER_RS485_ENABLED &&
- up->port.rs485_config == serial8250_em485_config)
+ if (port->rs485.flags & SER_RS485_ENABLED &&
+ port->rs485_config == serial8250_em485_config)
serial8250_em485_stop_tx(up, true);
}
@@ -377,7 +378,7 @@ static void omap_8250_set_termios(struct uart_port *port,
const struct ktermios *old)
{
struct uart_8250_port *up = up_to_u8250p(port);
- struct omap8250_priv *priv = up->port.private_data;
+ struct omap8250_priv *priv = port->private_data;
unsigned char cval = 0;
unsigned int baud;
@@ -418,39 +419,39 @@ static void omap_8250_set_termios(struct uart_port *port,
* ignoring of characters only occurs if the bit is set
* in @ignore_status_mask as well.
*/
- up->port.read_status_mask = UART_LSR_OE | UART_LSR_DR;
+ port->read_status_mask = UART_LSR_OE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
- up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+ port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
if (termios->c_iflag & (IGNBRK | PARMRK))
- up->port.read_status_mask |= UART_LSR_BI;
+ port->read_status_mask |= UART_LSR_BI;
/*
* Characters to ignore
*/
- up->port.ignore_status_mask = 0;
+ port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
- up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+ port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
if (termios->c_iflag & IGNBRK) {
- up->port.ignore_status_mask |= UART_LSR_BI;
+ port->ignore_status_mask |= UART_LSR_BI;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
- up->port.ignore_status_mask |= UART_LSR_OE;
+ port->ignore_status_mask |= UART_LSR_OE;
}
/*
* ignore all characters if CREAD is not set
*/
if ((termios->c_cflag & CREAD) == 0)
- up->port.ignore_status_mask |= UART_LSR_DR;
+ port->ignore_status_mask |= UART_LSR_DR;
/*
* Modem status interrupts
*/
up->ier &= ~UART_IER_MSI;
- if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+ if (UART_ENABLE_MS(port, termios->c_cflag))
up->ier |= UART_IER_MSI;
up->lcr = cval;
@@ -488,15 +489,15 @@ static void omap_8250_set_termios(struct uart_port *port,
priv->xoff = termios->c_cc[VSTOP];
priv->efr = 0;
- up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
+ port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
- if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW &&
+ if (termios->c_cflag & CRTSCTS && port->flags & UPF_HARD_FLOW &&
!mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS) &&
!mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_CTS)) {
/* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
- up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
+ port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
priv->efr |= UART_EFR_CTS;
- } else if (up->port.flags & UPF_SOFT_FLOW) {
+ } else if (port->flags & UPF_SOFT_FLOW) {
/*
* OMAP rx s/w flow control is borked; the transmitter remains
* stuck off even if rx flow control is subsequently disabled
@@ -508,7 +509,7 @@ static void omap_8250_set_termios(struct uart_port *port,
* Transmit XON1, XOFF1
*/
if (termios->c_iflag & IXOFF) {
- up->port.status |= UPSTAT_AUTOXOFF;
+ port->status |= UPSTAT_AUTOXOFF;
priv->efr |= OMAP_UART_SW_TX;
}
}
@@ -770,7 +771,7 @@ static int omap_8250_startup(struct uart_port *port)
uart_port_unlock_irq(port);
}
- enable_irq(up->port.irq);
+ enable_irq(port->irq);
pm_runtime_mark_last_busy(port->dev);
pm_runtime_put_autosuspend(port->dev);
@@ -797,7 +798,7 @@ static void omap_8250_shutdown(struct uart_port *port)
up->ier = 0;
serial_out(up, UART_IER, 0);
uart_port_unlock_irq(port);
- disable_irq_nosync(up->port.irq);
+ disable_irq_nosync(port->irq);
dev_pm_clear_wake_irq(port->dev);
serial8250_release_dma(up);
@@ -1173,16 +1174,6 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
return 0;
}
- sg_init_table(&sg, 1);
- ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
- UART_XMIT_SIZE, dma->tx_addr);
- if (ret != 1) {
- serial8250_clear_THRI(p);
- return 0;
- }
-
- dma->tx_size = sg_dma_len(&sg);
-
if (priv->habit & OMAP_DMA_TX_KICK) {
unsigned char c;
u8 tx_lvl;
@@ -1207,18 +1198,22 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
ret = -EBUSY;
goto err;
}
- if (dma->tx_size < 4) {
+ if (kfifo_len(&tport->xmit_fifo) < 4) {
ret = -EINVAL;
goto err;
}
- if (!kfifo_get(&tport->xmit_fifo, &c)) {
+ if (!uart_fifo_out(&p->port, &c, 1)) {
ret = -EINVAL;
goto err;
}
skip_byte = c;
- /* now we need to recompute due to kfifo_get */
- kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
- UART_XMIT_SIZE, dma->tx_addr);
+ }
+
+ sg_init_table(&sg, 1);
+ ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1, UART_XMIT_SIZE, dma->tx_addr);
+ if (ret != 1) {
+ ret = -EINVAL;
+ goto err;
}
desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1, DMA_MEM_TO_DEV,
@@ -1228,6 +1223,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
goto err;
}
+ dma->tx_size = sg_dma_len(&sg);
dma->tx_running = 1;
desc->callback = omap_8250_dma_tx_complete;
@@ -1315,7 +1311,7 @@ static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir,
static int omap_8250_dma_handle_irq(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
- struct omap8250_priv *priv = up->port.private_data;
+ struct omap8250_priv *priv = port->private_data;
u16 status;
u8 iir;
@@ -1337,8 +1333,8 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
serial8250_modem_status(up);
if (status & UART_LSR_THRE && up->dma->tx_err) {
- if (uart_tx_stopped(&up->port) ||
- kfifo_is_empty(&up->port.state->port.xmit_fifo)) {
+ if (uart_tx_stopped(port) ||
+ kfifo_is_empty(&port->state->port.xmit_fifo)) {
up->dma->tx_err = 0;
serial8250_tx_chars(up);
} else {
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 73c200127b08..152f914c599d 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1751,7 +1751,7 @@ static int pci_fintek_init(struct pci_dev *dev)
return max_port;
}
-static void f815xxa_mem_serial_out(struct uart_port *p, int offset, int value)
+static void f815xxa_mem_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
struct f815xxa_data *data = p->private_data;
unsigned long flags;
@@ -1846,10 +1846,10 @@ static void kt_handle_break(struct uart_port *p)
serial8250_clear_and_reinit_fifos(up);
}
-static unsigned int kt_serial_in(struct uart_port *p, int offset)
+static u32 kt_serial_in(struct uart_port *p, unsigned int offset)
{
struct uart_8250_port *up = up_to_u8250p(p);
- unsigned int val;
+ u32 val;
/*
* When the Intel ME (management engine) gets reset its serial
diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c
index e9c51d4e447d..4c149db84692 100644
--- a/drivers/tty/serial/8250/8250_pci1xxxx.c
+++ b/drivers/tty/serial/8250/8250_pci1xxxx.c
@@ -115,6 +115,7 @@
#define UART_RESET_REG 0x94
#define UART_RESET_D3_RESET_DISABLE BIT(16)
+#define UART_RESET_HOT_RESET_DISABLE BIT(17)
#define UART_BURST_STATUS_REG 0x9C
#define UART_TX_BURST_FIFO 0xA0
@@ -620,6 +621,10 @@ static int pci1xxxx_suspend(struct device *dev)
}
data = readl(p + UART_RESET_REG);
+
+ if (priv->dev_rev >= 0xC0)
+ data |= UART_RESET_HOT_RESET_DISABLE;
+
writel(data | UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
if (wakeup)
@@ -647,7 +652,12 @@ static int pci1xxxx_resume(struct device *dev)
}
data = readl(p + UART_RESET_REG);
+
+ if (priv->dev_rev >= 0xC0)
+ data &= ~UART_RESET_HOT_RESET_DISABLE;
+
writel(data & ~UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
+
iounmap(p);
for (i = 0; i < priv->nr; i++) {
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 8ac452cea36c..2da9db960d09 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -39,15 +39,6 @@
#include "8250.h"
/*
- * Debugging.
- */
-#if 0
-#define DEBUG_AUTOCONF(fmt...) printk(fmt)
-#else
-#define DEBUG_AUTOCONF(fmt...) do { } while (0)
-#endif
-
-/*
* Here we define the default xmit fifo size used for each type of UART.
*/
static const struct serial8250_config uart_config[] = {
@@ -339,14 +330,14 @@ static void default_serial_dl_write(struct uart_8250_port *up, u32 value)
}
#ifdef CONFIG_HAS_IOPORT
-static unsigned int hub6_serial_in(struct uart_port *p, int offset)
+static u32 hub6_serial_in(struct uart_port *p, unsigned int offset)
{
offset = offset << p->regshift;
outb(p->hub6 - 1 + offset, p->iobase);
return inb(p->iobase + 1);
}
-static void hub6_serial_out(struct uart_port *p, int offset, int value)
+static void hub6_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
offset = offset << p->regshift;
outb(p->hub6 - 1 + offset, p->iobase);
@@ -354,73 +345,73 @@ static void hub6_serial_out(struct uart_port *p, int offset, int value)
}
#endif /* CONFIG_HAS_IOPORT */
-static unsigned int mem_serial_in(struct uart_port *p, int offset)
+static u32 mem_serial_in(struct uart_port *p, unsigned int offset)
{
offset = offset << p->regshift;
return readb(p->membase + offset);
}
-static void mem_serial_out(struct uart_port *p, int offset, int value)
+static void mem_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
offset = offset << p->regshift;
writeb(value, p->membase + offset);
}
-static void mem16_serial_out(struct uart_port *p, int offset, int value)
+static void mem16_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
offset = offset << p->regshift;
writew(value, p->membase + offset);
}
-static unsigned int mem16_serial_in(struct uart_port *p, int offset)
+static u32 mem16_serial_in(struct uart_port *p, unsigned int offset)
{
offset = offset << p->regshift;
return readw(p->membase + offset);
}
-static void mem32_serial_out(struct uart_port *p, int offset, int value)
+static void mem32_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
offset = offset << p->regshift;
writel(value, p->membase + offset);
}
-static unsigned int mem32_serial_in(struct uart_port *p, int offset)
+static u32 mem32_serial_in(struct uart_port *p, unsigned int offset)
{
offset = offset << p->regshift;
return readl(p->membase + offset);
}
-static void mem32be_serial_out(struct uart_port *p, int offset, int value)
+static void mem32be_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
offset = offset << p->regshift;
iowrite32be(value, p->membase + offset);
}
-static unsigned int mem32be_serial_in(struct uart_port *p, int offset)
+static u32 mem32be_serial_in(struct uart_port *p, unsigned int offset)
{
offset = offset << p->regshift;
return ioread32be(p->membase + offset);
}
#ifdef CONFIG_HAS_IOPORT
-static unsigned int io_serial_in(struct uart_port *p, int offset)
+static u32 io_serial_in(struct uart_port *p, unsigned int offset)
{
offset = offset << p->regshift;
return inb(p->iobase + offset);
}
-static void io_serial_out(struct uart_port *p, int offset, int value)
+static void io_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
offset = offset << p->regshift;
outb(value, p->iobase + offset);
}
#endif
-static unsigned int no_serial_in(struct uart_port *p, int offset)
+static u32 no_serial_in(struct uart_port *p, unsigned int offset)
{
- return (unsigned int)-1;
+ return ~0U;
}
-static void no_serial_out(struct uart_port *p, int offset, int value)
+static void no_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
}
@@ -517,22 +508,20 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
}
EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
-void serial8250_rpm_get(struct uart_8250_port *p)
+static void serial8250_rpm_get(struct uart_8250_port *p)
{
if (!(p->capabilities & UART_CAP_RPM))
return;
pm_runtime_get_sync(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_get);
-void serial8250_rpm_put(struct uart_8250_port *p)
+static void serial8250_rpm_put(struct uart_8250_port *p)
{
if (!(p->capabilities & UART_CAP_RPM))
return;
pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_put);
/**
* serial8250_em485_init() - put uart_8250_port into rs485 emulating
@@ -647,7 +636,7 @@ EXPORT_SYMBOL_GPL(serial8250_em485_config);
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is
* empty and the HW can idle again.
*/
-void serial8250_rpm_get_tx(struct uart_8250_port *p)
+static void serial8250_rpm_get_tx(struct uart_8250_port *p)
{
unsigned char rpm_active;
@@ -659,9 +648,8 @@ void serial8250_rpm_get_tx(struct uart_8250_port *p)
return;
pm_runtime_get_sync(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_get_tx);
-void serial8250_rpm_put_tx(struct uart_8250_port *p)
+static void serial8250_rpm_put_tx(struct uart_8250_port *p)
{
unsigned char rpm_active;
@@ -674,7 +662,6 @@ void serial8250_rpm_put_tx(struct uart_8250_port *p)
pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_put_tx);
/*
* IER sleep support. UARTs which have EFRs need the "extended
@@ -709,6 +696,15 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
serial8250_rpm_put(p);
}
+/* Clear the interrupt registers. */
+static void serial8250_clear_interrupts(struct uart_port *port)
+{
+ serial_port_in(port, UART_LSR);
+ serial_port_in(port, UART_RX);
+ serial_port_in(port, UART_IIR);
+ serial_port_in(port, UART_MSR);
+}
+
static void serial8250_clear_IER(struct uart_8250_port *up)
{
if (up->capabilities & UART_CAP_UUE)
@@ -717,75 +713,6 @@ static void serial8250_clear_IER(struct uart_8250_port *up)
serial_out(up, UART_IER, 0);
}
-#ifdef CONFIG_SERIAL_8250_RSA
-/*
- * Attempts to turn on the RSA FIFO. Returns zero on failure.
- * We set the port uart clock rate if we succeed.
- */
-static int __enable_rsa(struct uart_8250_port *up)
-{
- unsigned char mode;
- int result;
-
- mode = serial_in(up, UART_RSA_MSR);
- result = mode & UART_RSA_MSR_FIFO;
-
- if (!result) {
- serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
- mode = serial_in(up, UART_RSA_MSR);
- result = mode & UART_RSA_MSR_FIFO;
- }
-
- if (result)
- up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16;
-
- return result;
-}
-
-static void enable_rsa(struct uart_8250_port *up)
-{
- if (up->port.type == PORT_RSA) {
- if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
- uart_port_lock_irq(&up->port);
- __enable_rsa(up);
- uart_port_unlock_irq(&up->port);
- }
- if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
- serial_out(up, UART_RSA_FRR, 0);
- }
-}
-
-/*
- * Attempts to turn off the RSA FIFO. Returns zero on failure.
- * It is unknown why interrupts were disabled in here. However,
- * the caller is expected to preserve this behaviour by grabbing
- * the spinlock before calling this function.
- */
-static void disable_rsa(struct uart_8250_port *up)
-{
- unsigned char mode;
- int result;
-
- if (up->port.type == PORT_RSA &&
- up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
- uart_port_lock_irq(&up->port);
-
- mode = serial_in(up, UART_RSA_MSR);
- result = !(mode & UART_RSA_MSR_FIFO);
-
- if (!result) {
- serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
- mode = serial_in(up, UART_RSA_MSR);
- result = !(mode & UART_RSA_MSR_FIFO);
- }
-
- if (result)
- up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
- uart_port_unlock_irq(&up->port);
- }
-}
-#endif /* CONFIG_SERIAL_8250_RSA */
-
/*
* This is a quickie test to see how big the FIFO is.
* It doesn't work at all the time, more's the pity.
@@ -889,8 +816,6 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
id3 = serial_icr_read(up, UART_ID3);
rev = serial_icr_read(up, UART_REV);
- DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev);
-
if (id1 == 0x16 && id2 == 0xC9 &&
(id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) {
up->port.type = PORT_16C950;
@@ -914,7 +839,6 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
* 0x14 - XR16C854.
*/
id1 = autoconfig_read_divisor_id(up);
- DEBUG_AUTOCONF("850id=%04x ", id1);
id2 = id1 >> 8;
if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) {
@@ -1001,7 +925,6 @@ static void autoconfig_16550a(struct uart_8250_port *up)
if (serial_in(up, UART_EFR) == 0) {
serial_out(up, UART_EFR, 0xA8);
if (serial_in(up, UART_EFR) != 0) {
- DEBUG_AUTOCONF("EFRv1 ");
up->port.type = PORT_16650;
up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
} else {
@@ -1014,8 +937,6 @@ static void autoconfig_16550a(struct uart_8250_port *up)
if (status1 == UART_IIR_FIFO_ENABLED_16750)
up->port.type = PORT_16550A_FSL64;
- else
- DEBUG_AUTOCONF("Motorola 8xxx DUART ");
}
serial_out(up, UART_EFR, 0);
return;
@@ -1027,7 +948,6 @@ static void autoconfig_16550a(struct uart_8250_port *up)
*/
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) {
- DEBUG_AUTOCONF("EFRv2 ");
autoconfig_has_efr(up);
return;
}
@@ -1090,8 +1010,6 @@ static void autoconfig_16550a(struct uart_8250_port *up)
serial_out(up, UART_LCR, 0);
- DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2);
-
if (status1 == UART_IIR_FIFO_ENABLED_16550A &&
status2 == UART_IIR_FIFO_ENABLED_16750) {
up->port.type = PORT_16750;
@@ -1120,17 +1038,10 @@ static void autoconfig_16550a(struct uart_8250_port *up)
* It's an Xscale.
* We'll leave the UART_IER_UUE bit set to 1 (enabled).
*/
- DEBUG_AUTOCONF("Xscale ");
up->port.type = PORT_XSCALE;
up->capabilities |= UART_CAP_UUE | UART_CAP_RTOIE;
return;
}
- } else {
- /*
- * If we got here we couldn't force the IER_UUE bit to 0.
- * Log it and continue.
- */
- DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 ");
}
serial_out(up, UART_IER, iersave);
@@ -1162,9 +1073,6 @@ static void autoconfig(struct uart_8250_port *up)
if (!port->iobase && !port->mapbase && !port->membase)
return;
- DEBUG_AUTOCONF("%s: autoconf (0x%04lx, 0x%p): ",
- port->name, port->iobase, port->membase);
-
/*
* We really do need global IRQs disabled here - we're going to
* be frobbing the chips IRQ enable register to see if it exists.
@@ -1211,9 +1119,7 @@ static void autoconfig(struct uart_8250_port *up)
* We failed; there's nothing here
*/
uart_port_unlock_irqrestore(port, flags);
- DEBUG_AUTOCONF("IER test failed (%02x, %02x) ",
- scratch2, scratch3);
- goto out;
+ return;
}
}
@@ -1235,9 +1141,7 @@ static void autoconfig(struct uart_8250_port *up)
serial8250_out_MCR(up, save_mcr);
if (status1 != (UART_MSR_DCD | UART_MSR_CTS)) {
uart_port_unlock_irqrestore(port, flags);
- DEBUG_AUTOCONF("LOOP test failed (%02x) ",
- status1);
- goto out;
+ return;
}
}
@@ -1271,14 +1175,7 @@ static void autoconfig(struct uart_8250_port *up)
break;
}
-#ifdef CONFIG_SERIAL_8250_RSA
- /*
- * Only probe for RSA ports if we got the region.
- */
- if (port->type == PORT_16550A && up->probe & UART_PROBE_RSA &&
- __enable_rsa(up))
- port->type = PORT_RSA;
-#endif
+ rsa_autoconfig(up);
serial_out(up, UART_LCR, save_lcr);
@@ -1287,22 +1184,17 @@ static void autoconfig(struct uart_8250_port *up)
up->capabilities = uart_config[port->type].flags;
up->tx_loadsz = uart_config[port->type].tx_loadsz;
- if (port->type == PORT_UNKNOWN)
- goto out_unlock;
-
- /*
- * Reset the UART.
- */
-#ifdef CONFIG_SERIAL_8250_RSA
- if (port->type == PORT_RSA)
- serial_out(up, UART_RSA_FRR, 0);
-#endif
- serial8250_out_MCR(up, save_mcr);
- serial8250_clear_fifos(up);
- serial_in(up, UART_RX);
- serial8250_clear_IER(up);
+ if (port->type != PORT_UNKNOWN) {
+ /*
+ * Reset the UART.
+ */
+ rsa_reset(up);
+ serial8250_out_MCR(up, save_mcr);
+ serial8250_clear_fifos(up);
+ serial_in(up, UART_RX);
+ serial8250_clear_IER(up);
+ }
-out_unlock:
uart_port_unlock_irqrestore(port, flags);
/*
@@ -1315,9 +1207,6 @@ out_unlock:
dev_warn(port->dev, "detected caps %08x should be %08x\n",
old_capabilities, up->capabilities);
}
-out:
- DEBUG_AUTOCONF("iir=%d ", scratch);
- DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name);
}
static void autoconfig_irq(struct uart_8250_port *up)
@@ -1358,10 +1247,7 @@ static void autoconfig_irq(struct uart_8250_port *up)
uart_port_lock_irq(port);
serial_out(up, UART_IER, UART_IER_ALL_INTR);
uart_port_unlock_irq(port);
- serial_in(up, UART_LSR);
- serial_in(up, UART_RX);
- serial_in(up, UART_IIR);
- serial_in(up, UART_MSR);
+ serial8250_clear_interrupts(port);
serial_out(up, UART_TX, 0xFF);
udelay(20);
irq = probe_irq_off(irqs);
@@ -2194,27 +2080,13 @@ static void serial8250_put_poll_char(struct uart_port *port,
#endif /* CONFIG_CONSOLE_POLL */
-int serial8250_do_startup(struct uart_port *port)
+static void serial8250_startup_special(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
- unsigned char iir;
- int retval;
- u16 lsr;
- if (!port->fifosize)
- port->fifosize = uart_config[port->type].fifo_size;
- if (!up->tx_loadsz)
- up->tx_loadsz = uart_config[port->type].tx_loadsz;
- if (!up->capabilities)
- up->capabilities = uart_config[port->type].flags;
- up->mcr = 0;
-
- if (port->iotype != up->cur_iotype)
- set_io_from_upio(port);
-
- serial8250_rpm_get(up);
- if (port->type == PORT_16C950) {
+ switch (port->type) {
+ case PORT_16C950:
/*
* Wake up and initialize UART
*
@@ -2231,9 +2103,8 @@ int serial8250_do_startup(struct uart_port *port)
serial_port_out(port, UART_EFR, UART_EFR_ECB);
serial_port_out(port, UART_LCR, 0);
uart_port_unlock_irqrestore(port, flags);
- }
-
- if (port->type == PORT_DA830) {
+ break;
+ case PORT_DA830:
/*
* Reset the port
*
@@ -2250,193 +2121,224 @@ int serial8250_do_startup(struct uart_port *port)
UART_DA830_PWREMU_MGMT_UTRST |
UART_DA830_PWREMU_MGMT_URRST |
UART_DA830_PWREMU_MGMT_FREE);
+ break;
+ case PORT_RSA:
+ rsa_enable(up);
+ break;
}
+}
-#ifdef CONFIG_SERIAL_8250_RSA
- /*
- * If this is an RSA port, see if we can kick it up to the
- * higher speed clock.
- */
- enable_rsa(up);
-#endif
-
- /*
- * Clear the FIFO buffers and disable them.
- * (they will be reenabled in set_termios())
- */
- serial8250_clear_fifos(up);
-
- /*
- * Clear the interrupt registers.
- */
- serial_port_in(port, UART_LSR);
- serial_port_in(port, UART_RX);
- serial_port_in(port, UART_IIR);
- serial_port_in(port, UART_MSR);
-
- /*
- * At this point, there's no way the LSR could still be 0xff;
- * if it is, then bail out, because there's likely no UART
- * here.
- */
- if (!(port->flags & UPF_BUGGY_UART) &&
- (serial_port_in(port, UART_LSR) == 0xff)) {
- dev_info_ratelimited(port->dev, "LSR safety check engaged!\n");
- retval = -ENODEV;
- goto out;
- }
+static void serial8250_set_TRG_levels(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
- /*
- * For a XR16C850, we need to set the trigger levels
- */
- if (port->type == PORT_16850) {
- unsigned char fctr;
+ switch (port->type) {
+ /* For a XR16C850, we need to set the trigger levels */
+ case PORT_16850: {
+ u8 fctr;
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
fctr = serial_in(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX);
- serial_port_out(port, UART_FCTR,
- fctr | UART_FCTR_TRGD | UART_FCTR_RX);
+ fctr |= UART_FCTR_TRGD;
+ serial_port_out(port, UART_FCTR, fctr | UART_FCTR_RX);
serial_port_out(port, UART_TRG, UART_TRG_96);
- serial_port_out(port, UART_FCTR,
- fctr | UART_FCTR_TRGD | UART_FCTR_TX);
+ serial_port_out(port, UART_FCTR, fctr | UART_FCTR_TX);
serial_port_out(port, UART_TRG, UART_TRG_96);
serial_port_out(port, UART_LCR, 0);
+ break;
}
+ /* For the Altera 16550 variants, set TX threshold trigger level. */
+ case PORT_ALTR_16550_F32:
+ case PORT_ALTR_16550_F64:
+ case PORT_ALTR_16550_F128:
+ if (port->fifosize <= 1)
+ return;
- /*
- * For the Altera 16550 variants, set TX threshold trigger level.
- */
- if (((port->type == PORT_ALTR_16550_F32) ||
- (port->type == PORT_ALTR_16550_F64) ||
- (port->type == PORT_ALTR_16550_F128)) && (port->fifosize > 1)) {
/* Bounds checking of TX threshold (valid 0 to fifosize-2) */
- if ((up->tx_loadsz < 2) || (up->tx_loadsz > port->fifosize)) {
+ if (up->tx_loadsz < 2 || up->tx_loadsz > port->fifosize) {
dev_err(port->dev, "TX FIFO Threshold errors, skipping\n");
- } else {
- serial_port_out(port, UART_ALTR_AFR,
- UART_ALTR_EN_TXFIFO_LW);
- serial_port_out(port, UART_ALTR_TX_LOW,
- port->fifosize - up->tx_loadsz);
- port->handle_irq = serial8250_tx_threshold_handle_irq;
+ return;
}
+ serial_port_out(port, UART_ALTR_AFR, UART_ALTR_EN_TXFIFO_LW);
+ serial_port_out(port, UART_ALTR_TX_LOW, port->fifosize - up->tx_loadsz);
+ port->handle_irq = serial8250_tx_threshold_handle_irq;
+ break;
}
+}
- /* Check if we need to have shared IRQs */
- if (port->irq && (up->port.flags & UPF_SHARE_IRQ))
- up->port.irqflags |= IRQF_SHARED;
-
- retval = up->ops->setup_irq(up);
- if (retval)
- goto out;
-
- if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) {
- unsigned char iir1;
+static void serial8250_THRE_test(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned long flags;
+ bool iir_noint1, iir_noint2;
- if (port->irqflags & IRQF_SHARED)
- disable_irq_nosync(port->irq);
+ if (!port->irq)
+ return;
- /*
- * Test for UARTs that do not reassert THRE when the
- * transmitter is idle and the interrupt has already
- * been cleared. Real 16550s should always reassert
- * this interrupt whenever the transmitter is idle and
- * the interrupt is enabled. Delays are necessary to
- * allow register changes to become visible.
- *
- * Synchronize UART_IER access against the console.
- */
- uart_port_lock_irqsave(port, &flags);
+ if (up->port.flags & UPF_NO_THRE_TEST)
+ return;
- wait_for_xmitr(up, UART_LSR_THRE);
- serial_port_out_sync(port, UART_IER, UART_IER_THRI);
- udelay(1); /* allow THRE to set */
- iir1 = serial_port_in(port, UART_IIR);
- serial_port_out(port, UART_IER, 0);
- serial_port_out_sync(port, UART_IER, UART_IER_THRI);
- udelay(1); /* allow a working UART time to re-assert THRE */
- iir = serial_port_in(port, UART_IIR);
- serial_port_out(port, UART_IER, 0);
+ if (port->irqflags & IRQF_SHARED)
+ disable_irq_nosync(port->irq);
- uart_port_unlock_irqrestore(port, flags);
+ /*
+ * Test for UARTs that do not reassert THRE when the transmitter is idle and the interrupt
+ * has already been cleared. Real 16550s should always reassert this interrupt whenever the
+ * transmitter is idle and the interrupt is enabled. Delays are necessary to allow register
+ * changes to become visible.
+ *
+ * Synchronize UART_IER access against the console.
+ */
+ uart_port_lock_irqsave(port, &flags);
- if (port->irqflags & IRQF_SHARED)
- enable_irq(port->irq);
+ wait_for_xmitr(up, UART_LSR_THRE);
+ serial_port_out_sync(port, UART_IER, UART_IER_THRI);
+ udelay(1); /* allow THRE to set */
+ iir_noint1 = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT;
+ serial_port_out(port, UART_IER, 0);
+ serial_port_out_sync(port, UART_IER, UART_IER_THRI);
+ udelay(1); /* allow a working UART time to re-assert THRE */
+ iir_noint2 = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT;
+ serial_port_out(port, UART_IER, 0);
- /*
- * If the interrupt is not reasserted, or we otherwise
- * don't trust the iir, setup a timer to kick the UART
- * on a regular basis.
- */
- if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) ||
- up->port.flags & UPF_BUG_THRE) {
- up->bugs |= UART_BUG_THRE;
- }
- }
+ uart_port_unlock_irqrestore(port, flags);
- up->ops->setup_timer(up);
+ if (port->irqflags & IRQF_SHARED)
+ enable_irq(port->irq);
/*
- * Now, initialize the UART
+ * If the interrupt is not reasserted, or we otherwise don't trust the iir, setup a timer to
+ * kick the UART on a regular basis.
*/
- serial_port_out(port, UART_LCR, UART_LCR_WLEN8);
+ if ((!iir_noint1 && iir_noint2) || up->port.flags & UPF_BUG_THRE)
+ up->bugs |= UART_BUG_THRE;
+}
- uart_port_lock_irqsave(port, &flags);
- if (up->port.flags & UPF_FOURPORT) {
- if (!up->port.irq)
- up->port.mctrl |= TIOCM_OUT1;
- } else
- /*
- * Most PC uarts need OUT2 raised to enable interrupts.
- */
+static void serial8250_init_mctrl(struct uart_port *port)
+{
+ if (port->flags & UPF_FOURPORT) {
+ if (!port->irq)
+ port->mctrl |= TIOCM_OUT1;
+ } else {
+ /* Most PC uarts need OUT2 raised to enable interrupts. */
if (port->irq)
- up->port.mctrl |= TIOCM_OUT2;
+ port->mctrl |= TIOCM_OUT2;
+ }
serial8250_set_mctrl(port, port->mctrl);
+}
+
+static void serial8250_iir_txen_test(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ bool lsr_temt, iir_noint;
+
+ if (port->quirks & UPQ_NO_TXEN_TEST)
+ return;
+
+ /* Do a quick test to see if we receive an interrupt when we enable the TX irq. */
+ serial_port_out(port, UART_IER, UART_IER_THRI);
+ lsr_temt = serial_port_in(port, UART_LSR) & UART_LSR_TEMT;
+ iir_noint = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT;
+ serial_port_out(port, UART_IER, 0);
/*
* Serial over Lan (SoL) hack:
- * Intel 8257x Gigabit ethernet chips have a 16550 emulation, to be
- * used for Serial Over Lan. Those chips take a longer time than a
- * normal serial device to signalize that a transmission data was
- * queued. Due to that, the above test generally fails. One solution
- * would be to delay the reading of iir. However, this is not
- * reliable, since the timeout is variable. So, let's just don't
- * test if we receive TX irq. This way, we'll never enable
- * UART_BUG_TXEN.
- */
- if (!(up->port.quirks & UPQ_NO_TXEN_TEST)) {
- /*
- * Do a quick test to see if we receive an interrupt when we
- * enable the TX irq.
- */
- serial_port_out(port, UART_IER, UART_IER_THRI);
- lsr = serial_port_in(port, UART_LSR);
- iir = serial_port_in(port, UART_IIR);
- serial_port_out(port, UART_IER, 0);
-
- if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
- if (!(up->bugs & UART_BUG_TXEN)) {
- up->bugs |= UART_BUG_TXEN;
- dev_dbg(port->dev, "enabling bad tx status workarounds\n");
- }
- } else {
- up->bugs &= ~UART_BUG_TXEN;
+ * Intel 8257x Gigabit ethernet chips have a 16550 emulation, to be used for Serial Over
+ * Lan. Those chips take a longer time than a normal serial device to signalize that a
+ * transmission data was queued. Due to that, the above test generally fails. One solution
+ * would be to delay the reading of iir. However, this is not reliable, since the timeout is
+ * variable. So, in case of UPQ_NO_TXEN_TEST, let's just don't test if we receive TX irq.
+ * This way, we'll never enable UART_BUG_TXEN.
+ */
+ if (lsr_temt && iir_noint) {
+ if (!(up->bugs & UART_BUG_TXEN)) {
+ up->bugs |= UART_BUG_TXEN;
+ dev_dbg(port->dev, "enabling bad tx status workarounds\n");
}
+ return;
}
+ /* FIXME: why is this needed? */
+ up->bugs &= ~UART_BUG_TXEN;
+}
+
+static void serial8250_initialize(struct uart_port *port)
+{
+ unsigned long flags;
+
+ uart_port_lock_irqsave(port, &flags);
+ serial_port_out(port, UART_LCR, UART_LCR_WLEN8);
+
+ serial8250_init_mctrl(port);
+ serial8250_iir_txen_test(port);
uart_port_unlock_irqrestore(port, flags);
+}
+
+int serial8250_do_startup(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ int retval;
+
+ if (!port->fifosize)
+ port->fifosize = uart_config[port->type].fifo_size;
+ if (!up->tx_loadsz)
+ up->tx_loadsz = uart_config[port->type].tx_loadsz;
+ if (!up->capabilities)
+ up->capabilities = uart_config[port->type].flags;
+ up->mcr = 0;
+
+ if (port->iotype != up->cur_iotype)
+ set_io_from_upio(port);
+
+ serial8250_rpm_get(up);
+
+ serial8250_startup_special(port);
+
+ /*
+ * Clear the FIFO buffers and disable them.
+ * (they will be reenabled in set_termios())
+ */
+ serial8250_clear_fifos(up);
+
+ serial8250_clear_interrupts(port);
+
+ /*
+ * At this point, there's no way the LSR could still be 0xff;
+ * if it is, then bail out, because there's likely no UART
+ * here.
+ */
+ if (!(port->flags & UPF_BUGGY_UART) &&
+ (serial_port_in(port, UART_LSR) == 0xff)) {
+ dev_info_ratelimited(port->dev, "LSR safety check engaged!\n");
+ retval = -ENODEV;
+ goto out;
+ }
+
+ serial8250_set_TRG_levels(port);
+
+ /* Check if we need to have shared IRQs */
+ if (port->irq && (up->port.flags & UPF_SHARE_IRQ))
+ up->port.irqflags |= IRQF_SHARED;
+
+ retval = up->ops->setup_irq(up);
+ if (retval)
+ goto out;
+
+ serial8250_THRE_test(port);
+
+ up->ops->setup_timer(up);
+
+ serial8250_initialize(port);
/*
* Clear the interrupt registers again for luck, and clear the
* saved flags to avoid getting false values from polling
* routines or the previous session.
*/
- serial_port_in(port, UART_LSR);
- serial_port_in(port, UART_RX);
- serial_port_in(port, UART_IIR);
- serial_port_in(port, UART_MSR);
+ serial8250_clear_interrupts(port);
up->lsr_saved_flags = 0;
up->msr_saved_flags = 0;
@@ -2525,12 +2427,7 @@ void serial8250_do_shutdown(struct uart_port *port)
serial_port_in(port, UART_LCR) & ~UART_LCR_SBC);
serial8250_clear_fifos(up);
-#ifdef CONFIG_SERIAL_8250_RSA
- /*
- * Reset the RSA board back to 115kbps compat mode.
- */
- disable_rsa(up);
-#endif
+ rsa_disable(up);
/*
* Read data port to reset things, and then unlink from
@@ -2559,9 +2456,7 @@ static void serial8250_flush_buffer(struct uart_port *port)
serial8250_tx_dma_flush(up);
}
-static unsigned int serial8250_do_get_divisor(struct uart_port *port,
- unsigned int baud,
- unsigned int *frac)
+static unsigned int serial8250_do_get_divisor(struct uart_port *port, unsigned int baud)
{
upf_t magic_multiplier = port->flags & UPF_MAGIC_MULTIPLIER;
struct uart_8250_port *up = up_to_u8250p(port);
@@ -2622,26 +2517,23 @@ static unsigned int serial8250_get_divisor(struct uart_port *port,
if (port->get_divisor)
return port->get_divisor(port, baud, frac);
- return serial8250_do_get_divisor(port, baud, frac);
+ return serial8250_do_get_divisor(port, baud);
}
-static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
- tcflag_t c_cflag)
+static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, tcflag_t c_cflag)
{
- unsigned char cval;
-
- cval = UART_LCR_WLEN(tty_get_char_size(c_cflag));
+ u8 lcr = UART_LCR_WLEN(tty_get_char_size(c_cflag));
if (c_cflag & CSTOPB)
- cval |= UART_LCR_STOP;
+ lcr |= UART_LCR_STOP;
if (c_cflag & PARENB)
- cval |= UART_LCR_PARITY;
+ lcr |= UART_LCR_PARITY;
if (!(c_cflag & PARODD))
- cval |= UART_LCR_EPAR;
+ lcr |= UART_LCR_EPAR;
if (c_cflag & CMSPAR)
- cval |= UART_LCR_SPAR;
+ lcr |= UART_LCR_SPAR;
- return cval;
+ return lcr;
}
void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
@@ -2748,65 +2640,62 @@ out_unlock:
}
EXPORT_SYMBOL_GPL(serial8250_update_uartclk);
-void
-serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
- const struct ktermios *old)
+static void serial8250_set_mini(struct uart_port *port, struct ktermios *termios)
{
struct uart_8250_port *up = up_to_u8250p(port);
- unsigned char cval;
- unsigned long flags;
- unsigned int baud, quot, frac = 0;
- if (up->capabilities & UART_CAP_MINI) {
- termios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CMSPAR);
- if ((termios->c_cflag & CSIZE) == CS5 ||
- (termios->c_cflag & CSIZE) == CS6)
- termios->c_cflag = (termios->c_cflag & ~CSIZE) | CS7;
+ if (!(up->capabilities & UART_CAP_MINI))
+ return;
+
+ termios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CMSPAR);
+
+ tcflag_t csize = termios->c_cflag & CSIZE;
+ if (csize == CS5 || csize == CS6) {
+ termios->c_cflag &= ~CSIZE;
+ termios->c_cflag |= CS7;
}
- cval = serial8250_compute_lcr(up, termios->c_cflag);
+}
- baud = serial8250_get_baud_rate(port, termios, old);
- quot = serial8250_get_divisor(port, baud, &frac);
+static void serial8250_set_trigger_for_slow_speed(struct uart_port *port, struct ktermios *termios,
+ unsigned int baud)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
- /*
- * Ok, we're now changing the port state. Do it with
- * interrupts disabled.
- *
- * Synchronize UART_IER access against the console.
- */
- serial8250_rpm_get(up);
- uart_port_lock_irqsave(port, &flags);
+ if (!(up->capabilities & UART_CAP_FIFO))
+ return;
+ if (port->fifosize <= 1)
+ return;
+ if (baud >= 2400)
+ return;
+ if (up->dma)
+ return;
- up->lcr = cval; /* Save computed LCR */
+ up->fcr &= ~UART_FCR_TRIGGER_MASK;
+ up->fcr |= UART_FCR_TRIGGER_1;
+}
- if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
- if (baud < 2400 && !up->dma) {
- up->fcr &= ~UART_FCR_TRIGGER_MASK;
- up->fcr |= UART_FCR_TRIGGER_1;
- }
- }
+/*
+ * MCR-based auto flow control. When AFE is enabled, RTS will be deasserted when the receive FIFO
+ * contains more characters than the trigger, or the MCR RTS bit is cleared.
+ */
+static void serial8250_set_afe(struct uart_port *port, struct ktermios *termios)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
- /*
- * MCR-based auto flow control. When AFE is enabled, RTS will be
- * deasserted when the receive FIFO contains more characters than
- * the trigger, or the MCR RTS bit is cleared.
- */
- if (up->capabilities & UART_CAP_AFE) {
- up->mcr &= ~UART_MCR_AFE;
- if (termios->c_cflag & CRTSCTS)
- up->mcr |= UART_MCR_AFE;
- }
+ if (!(up->capabilities & UART_CAP_AFE))
+ return;
- /*
- * Update the per-port timeout.
- */
- uart_update_timeout(port, termios->c_cflag, baud);
+ up->mcr &= ~UART_MCR_AFE;
+ if (termios->c_cflag & CRTSCTS)
+ up->mcr |= UART_MCR_AFE;
+}
+static void serial8250_set_errors_and_ignores(struct uart_port *port, struct ktermios *termios)
+{
/*
- * Specify which conditions may be considered for error
- * handling and the ignoring of characters. The actual
- * ignoring of characters only occurs if the bit is set
- * in @ignore_status_mask as well.
+ * Specify which conditions may be considered for error handling and the ignoring of
+ * characters. The actual ignoring of characters only occurs if the bit is set in
+ * @ignore_status_mask as well.
*/
port->read_status_mask = UART_LSR_OE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
@@ -2814,34 +2703,32 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
port->read_status_mask |= UART_LSR_BI;
- /*
- * Characters to ignore
- */
+ /* Characters to ignore */
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= UART_LSR_BI;
/*
- * If we're ignoring parity and break indicators,
- * ignore overruns too (for real raw support).
+ * If we're ignoring parity and break indicators, ignore overruns too (for real raw
+ * support).
*/
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UART_LSR_OE;
}
- /*
- * ignore all characters if CREAD is not set
- */
+ /* ignore all characters if CREAD is not set */
if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= UART_LSR_DR;
+}
- /*
- * CTS flow control flag and modem status interrupts
- */
+static void serial8250_set_ier(struct uart_port *port, struct ktermios *termios)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ /* CTS flow control flag and modem status interrupts */
up->ier &= ~UART_IER_MSI;
- if (!(up->bugs & UART_BUG_NOMSR) &&
- UART_ENABLE_MS(&up->port, termios->c_cflag))
+ if (!(up->bugs & UART_BUG_NOMSR) && UART_ENABLE_MS(&up->port, termios->c_cflag))
up->ier |= UART_IER_MSI;
if (up->capabilities & UART_CAP_UUE)
up->ier |= UART_IER_UUE;
@@ -2849,41 +2736,90 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
up->ier |= UART_IER_RTOIE;
serial_port_out(port, UART_IER, up->ier);
+}
- if (up->capabilities & UART_CAP_EFR) {
- unsigned char efr = 0;
- /*
- * TI16C752/Startech hardware flow control. FIXME:
- * - TI16C752 requires control thresholds to be set.
- * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled.
- */
- if (termios->c_cflag & CRTSCTS)
- efr |= UART_EFR_CTS;
-
- serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B);
- if (port->flags & UPF_EXAR_EFR)
- serial_port_out(port, UART_XR_EFR, efr);
- else
- serial_port_out(port, UART_EFR, efr);
- }
+static void serial8250_set_efr(struct uart_port *port, struct ktermios *termios)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ u8 efr_reg = UART_EFR;
+ u8 efr = 0;
- serial8250_set_divisor(port, baud, quot, frac);
+ if (!(up->capabilities & UART_CAP_EFR))
+ return;
/*
- * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
- * is written without DLAB set, this mode will be disabled.
+ * TI16C752/Startech hardware flow control. FIXME:
+ * - TI16C752 requires control thresholds to be set.
+ * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled.
*/
- if (port->type == PORT_16750)
+ if (termios->c_cflag & CRTSCTS)
+ efr |= UART_EFR_CTS;
+
+ if (port->flags & UPF_EXAR_EFR)
+ efr_reg = UART_XR_EFR;
+
+ serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B);
+ serial_port_out(port, efr_reg, efr);
+}
+
+static void serial8250_set_fcr(struct uart_port *port, struct ktermios *termios)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ bool is_16750 = port->type == PORT_16750;
+
+ if (is_16750)
serial_port_out(port, UART_FCR, up->fcr);
- serial_port_out(port, UART_LCR, up->lcr); /* reset DLAB */
- if (port->type != PORT_16750) {
- /* emulated UARTs (Lucent Venus 167x) need two steps */
- if (up->fcr & UART_FCR_ENABLE_FIFO)
- serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_port_out(port, UART_FCR, up->fcr); /* set fcr */
- }
+ /*
+ * LCR DLAB must be reset to enable 64-byte FIFO mode. If the FCR is written without DLAB
+ * set, this mode will be disabled.
+ */
+ serial_port_out(port, UART_LCR, up->lcr);
+
+ if (is_16750)
+ return;
+
+ /* emulated UARTs (Lucent Venus 167x) need two steps */
+ if (up->fcr & UART_FCR_ENABLE_FIFO)
+ serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO);
+
+ serial_port_out(port, UART_FCR, up->fcr);
+}
+
+void
+serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
+ const struct ktermios *old)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned long flags;
+ unsigned int baud, quot, frac = 0;
+ u8 lcr;
+
+ serial8250_set_mini(port, termios);
+ lcr = serial8250_compute_lcr(up, termios->c_cflag);
+ baud = serial8250_get_baud_rate(port, termios, old);
+ quot = serial8250_get_divisor(port, baud, &frac);
+
+ /*
+ * Ok, we're now changing the port state. Do it with
+ * interrupts disabled.
+ *
+ * Synchronize UART_IER access against the console.
+ */
+ serial8250_rpm_get(up);
+ uart_port_lock_irqsave(port, &flags);
+
+ up->lcr = lcr;
+ serial8250_set_trigger_for_slow_speed(port, termios, baud);
+ serial8250_set_afe(port, termios);
+ uart_update_timeout(port, termios->c_cflag, baud);
+ serial8250_set_errors_and_ignores(port, termios);
+ serial8250_set_ier(port, termios);
+ serial8250_set_efr(port, termios);
+ serial8250_set_divisor(port, baud, quot, frac);
+ serial8250_set_fcr(port, termios);
serial8250_set_mctrl(port, port->mctrl);
+
uart_port_unlock_irqrestore(port, flags);
serial8250_rpm_put(up);
@@ -2993,6 +2929,8 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
if (!request_region(port->iobase, size, "serial"))
return -EBUSY;
return 0;
+ case UPIO_UNKNOWN:
+ break;
}
return 0;
@@ -3025,6 +2963,8 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_PORT:
release_region(port->iobase, size);
break;
+ case UPIO_UNKNOWN:
+ break;
}
}
diff --git a/drivers/tty/serial/8250/8250_rsa.c b/drivers/tty/serial/8250/8250_rsa.c
index 82f2593b4c59..d34093cc03ad 100644
--- a/drivers/tty/serial/8250/8250_rsa.c
+++ b/drivers/tty/serial/8250/8250_rsa.c
@@ -43,6 +43,8 @@ static void rsa8250_release_resource(struct uart_8250_port *up)
case UPIO_PORT:
release_region(port->iobase + offset, size);
break;
+ default:
+ break;
}
}
@@ -105,6 +107,102 @@ void univ8250_rsa_support(struct uart_ops *ops)
module_param_hw_array(probe_rsa, ulong, ioport, &probe_rsa_count, 0444);
MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
+/*
+ * Attempts to turn on the RSA FIFO. Returns zero on failure.
+ * We set the port uart clock rate if we succeed.
+ */
+static int __rsa_enable(struct uart_8250_port *up)
+{
+ unsigned char mode;
+ int result;
+
+ mode = serial_in(up, UART_RSA_MSR);
+ result = mode & UART_RSA_MSR_FIFO;
+
+ if (!result) {
+ serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+ mode = serial_in(up, UART_RSA_MSR);
+ result = mode & UART_RSA_MSR_FIFO;
+ }
+
+ if (result)
+ up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16;
+
+ return result;
+}
+
+/*
+ * If this is an RSA port, see if we can kick it up to the higher speed clock.
+ */
+void rsa_enable(struct uart_8250_port *up)
+{
+ if (up->port.type != PORT_RSA)
+ return;
+
+ if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
+ uart_port_lock_irq(&up->port);
+ __rsa_enable(up);
+ uart_port_unlock_irq(&up->port);
+ }
+ if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
+ serial_out(up, UART_RSA_FRR, 0);
+}
+EXPORT_SYMBOL_GPL_FOR_MODULES(rsa_enable, "8250_base");
+
+/*
+ * Attempts to turn off the RSA FIFO and resets the RSA board back to 115kbps compat mode. It is
+ * unknown why interrupts were disabled in here. However, the caller is expected to preserve this
+ * behaviour by grabbing the spinlock before calling this function.
+ */
+void rsa_disable(struct uart_8250_port *up)
+{
+ unsigned char mode;
+ int result;
+
+ if (up->port.type != PORT_RSA)
+ return;
+
+ if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16)
+ return;
+
+ uart_port_lock_irq(&up->port);
+ mode = serial_in(up, UART_RSA_MSR);
+ result = !(mode & UART_RSA_MSR_FIFO);
+
+ if (!result) {
+ serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+ mode = serial_in(up, UART_RSA_MSR);
+ result = !(mode & UART_RSA_MSR_FIFO);
+ }
+
+ if (result)
+ up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
+ uart_port_unlock_irq(&up->port);
+}
+EXPORT_SYMBOL_GPL_FOR_MODULES(rsa_disable, "8250_base");
+
+void rsa_autoconfig(struct uart_8250_port *up)
+{
+ /* Only probe for RSA ports if we got the region. */
+ if (up->port.type != PORT_16550A)
+ return;
+ if (!(up->probe & UART_PROBE_RSA))
+ return;
+
+ if (__rsa_enable(up))
+ up->port.type = PORT_RSA;
+}
+EXPORT_SYMBOL_GPL_FOR_MODULES(rsa_autoconfig, "8250_base");
+
+void rsa_reset(struct uart_8250_port *up)
+{
+ if (up->port.type != PORT_RSA)
+ return;
+
+ serial_out(up, UART_RSA_FRR, 0);
+}
+EXPORT_SYMBOL_GPL_FOR_MODULES(rsa_reset, "8250_base");
+
#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
#ifndef MODULE
/*
diff --git a/drivers/tty/serial/8250/8250_rt288x.c b/drivers/tty/serial/8250/8250_rt288x.c
index 6415ca8d3adf..bf28b8a9a710 100644
--- a/drivers/tty/serial/8250/8250_rt288x.c
+++ b/drivers/tty/serial/8250/8250_rt288x.c
@@ -33,7 +33,7 @@ static const u8 au_io_out_map[5] = {
[UART_MCR] = 6,
};
-static unsigned int au_serial_in(struct uart_port *p, int offset)
+static u32 au_serial_in(struct uart_port *p, unsigned int offset)
{
if (offset >= ARRAY_SIZE(au_io_in_map))
return UINT_MAX;
@@ -42,7 +42,7 @@ static unsigned int au_serial_in(struct uart_port *p, int offset)
return __raw_readl(p->membase + (offset << p->regshift));
}
-static void au_serial_out(struct uart_port *p, int offset, int value)
+static void au_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
if (offset >= ARRAY_SIZE(au_io_out_map))
return;
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
index 4874a9632db3..e3db60bf50c9 100644
--- a/drivers/tty/serial/8250/8250_uniphier.c
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -63,7 +63,7 @@ OF_EARLYCON_DECLARE(uniphier, "socionext,uniphier-uart",
* The register map is slightly different from that of 8250.
* IO callbacks must be overridden for correct access to FCR, LCR, MCR and SCR.
*/
-static unsigned int uniphier_serial_in(struct uart_port *p, int offset)
+static u32 uniphier_serial_in(struct uart_port *p, unsigned int offset)
{
unsigned int valshift = 0;
@@ -92,7 +92,7 @@ static unsigned int uniphier_serial_in(struct uart_port *p, int offset)
return (readl(p->membase + offset) >> valshift) & 0xff;
}
-static void uniphier_serial_out(struct uart_port *p, int offset, int value)
+static void uniphier_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
unsigned int valshift = 0;
bool normal = false;
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index bd3d636ff962..f64ef0819cd4 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -572,7 +572,7 @@ config SERIAL_8250_BCM7271
config SERIAL_8250_NI
tristate "NI 16550 based serial port"
depends on SERIAL_8250
- depends on (X86 && ACPI) || COMPILE_TEST
+ depends on X86 || COMPILE_TEST
help
This driver supports the integrated serial ports on National
Instruments (NI) controller hardware. This is required for all NI
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index b04eeda03b23..513a0941c284 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -24,6 +24,9 @@ obj-$(CONFIG_SERIAL_8250_ASPEED_VUART) += 8250_aspeed_vuart.o
obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o
obj-$(CONFIG_SERIAL_8250_BCM7271) += 8250_bcm7271.o
obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
+ifeq ($(CONFIG_SERIAL_8250),y)
+obj-$(CONFIG_X86_INTEL_CE) += 8250_ce4100.o
+endif
obj-$(CONFIG_SERIAL_8250_DFL) += 8250_dfl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 79a8186d3361..44427415a80d 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -675,6 +675,13 @@ config SERIAL_SH_SCI_DMA
depends on SERIAL_SH_SCI && DMA_ENGINE
default ARCH_RENESAS
+config SERIAL_RSCI
+ tristate "Support for Renesas RZ/T2H SCI variant"
+ depends on SERIAL_SH_SCI
+ help
+ Support for the RZ/T2H SCI variant with fifo.
+ Say Y if you want to be able to use the RZ/T2H SCI serial port.
+
config SERIAL_HS_LPC32XX
tristate "LPC32XX high speed serial port support"
depends on ARCH_LPC32XX || COMPILE_TEST
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index d58d9f719889..a2ccbc508ec5 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_SERIAL_QCOM_GENI) += qcom_geni_serial.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
obj-$(CONFIG_SERIAL_RDA) += rda-uart.o
obj-$(CONFIG_SERIAL_RP2) += rp2.o
+obj-$(CONFIG_SERIAL_RSCI) += rsci.o
obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
obj-$(CONFIG_SERIAL_SAMSUNG) += samsung_tty.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 011f38681131..837991dc4db9 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -275,7 +275,7 @@ static irqreturn_t altera_uart_interrupt(int irq, void *data)
static void altera_uart_timer(struct timer_list *t)
{
- struct altera_uart *pp = from_timer(pp, t, tmr);
+ struct altera_uart *pp = timer_container_of(pp, t, tmr);
struct uart_port *port = &pp->port;
altera_uart_interrupt(0, port);
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 11d65097578c..22939841b1de 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1046,7 +1046,7 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
*/
static void pl011_dma_rx_poll(struct timer_list *t)
{
- struct uart_amba_port *uap = from_timer(uap, t, dmarx.timer);
+ struct uart_amba_port *uap = timer_container_of(uap, t, dmarx.timer);
struct tty_port *port = &uap->port.state->port;
struct pl011_dmarx_data *dmarx = &uap->dmarx;
struct dma_chan *rxchan = uap->dmarx.chan;
@@ -2476,7 +2476,7 @@ static int pl011_console_setup(struct console *co, char *options)
static int pl011_console_match(struct console *co, char *name, int idx,
char *options)
{
- unsigned char iotype;
+ enum uart_iotype iotype;
resource_size_t addr;
int i;
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 18dba502144d..08dd8f887956 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -1266,8 +1266,8 @@ chan_err:
static void atmel_uart_timer_callback(struct timer_list *t)
{
- struct atmel_uart_port *atmel_port = from_timer(atmel_port, t,
- uart_timer);
+ struct atmel_uart_port *atmel_port = timer_container_of(atmel_port, t,
+ uart_timer);
struct uart_port *port = &atmel_port->uart;
if (!atomic_read(&atmel_port->tasklet_shutdown)) {
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index fe5aed99d55a..c9519e649e82 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -318,27 +318,27 @@ static const struct lpuart_soc_data ls1028a_data = {
.rx_watermark = 0,
};
-static struct lpuart_soc_data imx7ulp_data = {
+static const struct lpuart_soc_data imx7ulp_data = {
.devtype = IMX7ULP_LPUART,
.iotype = UPIO_MEM32,
.reg_off = IMX_REG_OFF,
.rx_watermark = 1,
};
-static struct lpuart_soc_data imx8ulp_data = {
+static const struct lpuart_soc_data imx8ulp_data = {
.devtype = IMX8ULP_LPUART,
.iotype = UPIO_MEM32,
.reg_off = IMX_REG_OFF,
.rx_watermark = 3,
};
-static struct lpuart_soc_data imx8qxp_data = {
+static const struct lpuart_soc_data imx8qxp_data = {
.devtype = IMX8QXP_LPUART,
.iotype = UPIO_MEM32,
.reg_off = IMX_REG_OFF,
.rx_watermark = 7, /* A lower watermark is ideal for low baud rates. */
};
-static struct lpuart_soc_data imxrt1050_data = {
+static const struct lpuart_soc_data imxrt1050_data = {
.devtype = IMXRT1050_LPUART,
.iotype = UPIO_MEM32,
.reg_off = IMX_REG_OFF,
@@ -403,6 +403,8 @@ static inline void lpuart32_write(struct uart_port *port, u32 val,
case UPIO_MEM32BE:
iowrite32be(val, port->membase + off);
break;
+ default:
+ break;
}
}
@@ -563,8 +565,9 @@ static dma_addr_t lpuart_dma_datareg_addr(struct lpuart_port *sport)
return sport->port.mapbase + UARTDATA;
case UPIO_MEM32BE:
return sport->port.mapbase + UARTDATA + sizeof(u32) - 1;
+ default:
+ return sport->port.mapbase + UARTDR;
}
- return sport->port.mapbase + UARTDR;
}
static int lpuart_dma_tx_request(struct uart_port *port)
@@ -1304,7 +1307,7 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
*/
static void lpuart_timer_func(struct timer_list *t)
{
- struct lpuart_port *sport = from_timer(sport, t, lpuart_timer);
+ struct lpuart_port *sport = timer_container_of(sport, t, lpuart_timer);
enum dma_status dmastat;
struct dma_chan *chan = sport->dma_rx_chan;
struct circ_buf *ring = &sport->rx_ring;
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index e4b6f1bfdc95..500dfc009d03 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -235,6 +235,7 @@ struct imx_port {
enum imx_tx_state tx_state;
struct hrtimer trigger_start_tx;
struct hrtimer trigger_stop_tx;
+ unsigned int rxtl;
};
struct imx_port_ucrs {
@@ -1165,7 +1166,7 @@ static void imx_uart_break_ctl(struct uart_port *port, int break_state)
*/
static void imx_uart_timeout(struct timer_list *t)
{
- struct imx_port *sport = from_timer(sport, t, timer);
+ struct imx_port *sport = timer_container_of(sport, t, timer);
unsigned long flags;
if (sport->port.state) {
@@ -1339,6 +1340,7 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport)
#define TXTL_DEFAULT 8
#define RXTL_DEFAULT 8 /* 8 characters or aging timer */
+#define RXTL_CONSOLE_DEFAULT 1
#define TXTL_DMA 8 /* DMA burst setting */
#define RXTL_DMA 9 /* DMA burst setting */
@@ -1457,7 +1459,7 @@ static void imx_uart_disable_dma(struct imx_port *sport)
ucr1 &= ~(UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN);
imx_uart_writel(sport, ucr1, UCR1);
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
sport->dma_is_enabled = 0;
}
@@ -1482,7 +1484,12 @@ static int imx_uart_startup(struct uart_port *port)
return retval;
}
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ if (uart_console(&sport->port))
+ sport->rxtl = RXTL_CONSOLE_DEFAULT;
+ else
+ sport->rxtl = RXTL_DEFAULT;
+
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
/* disable the DREN bit (Data Ready interrupt enable) before
* requesting IRQs
@@ -1948,7 +1955,7 @@ static int imx_uart_poll_init(struct uart_port *port)
if (retval)
clk_disable_unprepare(sport->clk_ipg);
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
uart_port_lock_irqsave(&sport->port, &flags);
@@ -2040,7 +2047,7 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
/* If the receiver trigger is 0, set it to a default value */
ufcr = imx_uart_readl(sport, UFCR);
if ((ufcr & UFCR_RXTL_MASK) == 0)
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
imx_uart_start_rx(port);
}
@@ -2302,7 +2309,7 @@ imx_uart_console_setup(struct console *co, char *options)
else
imx_uart_console_get_options(sport, &baud, &parity, &bits);
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index ce0fef7e2c66..be2f130696b3 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -451,6 +451,7 @@ int jsm_uart_port_init(struct jsm_board *brd)
if (!brd->channels[i])
continue;
+ brd->channels[i]->uart_port.dev = &brd->pci_dev->dev;
brd->channels[i]->uart_port.irq = brd->irq;
brd->channels[i]->uart_port.uartclk = 14745600;
brd->channels[i]->uart_port.type = PORT_JSM;
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 58a3ab030d67..62cd9e0bb377 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -773,10 +773,8 @@ static int fetch_irq_intel(struct device *dev, struct ltq_uart_port *ltq_port)
int ret;
ret = platform_get_irq(to_platform_device(dev), 0);
- if (ret < 0) {
- dev_err(dev, "failed to fetch IRQ for serial port\n");
+ if (ret < 0)
return ret;
- }
ltq_port->common_irq = ret;
port->irq = ret;
diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c
index 3a0960c97c77..6429e8f11f36 100644
--- a/drivers/tty/serial/liteuart.c
+++ b/drivers/tty/serial/liteuart.c
@@ -152,7 +152,7 @@ static irqreturn_t liteuart_interrupt(int irq, void *data)
static void liteuart_timer(struct timer_list *t)
{
- struct liteuart_port *uart = from_timer(uart, t, timer);
+ struct liteuart_port *uart = timer_container_of(uart, t, timer);
struct uart_port *port = &uart->port;
liteuart_interrupt(0, port);
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index f2dd83692b2c..67d80f8f801e 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -16,6 +16,7 @@
/* 4 MAX3100s should be enough for everyone */
#define MAX_MAX3100 4
+#include <linux/bitops.h>
#include <linux/container_of.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -133,7 +134,7 @@ static int max3100_do_parity(struct max3100_port *s, u16 c)
else
c &= 0xff;
- parity = parity ^ (hweight8(c) & 1);
+ parity = parity ^ parity8(c);
return parity;
}
@@ -308,7 +309,7 @@ static void max3100_dowork(struct max3100_port *s)
static void max3100_timeout(struct timer_list *t)
{
- struct max3100_port *s = from_timer(s, t, timer);
+ struct max3100_port *s = timer_container_of(s, t, timer);
max3100_dowork(s);
mod_timer(&s->timer, jiffies + uart_poll_timeout(&s->port));
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 35369a2f77b2..541c790c0109 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1189,13 +1189,16 @@ static int max310x_gpio_get(struct gpio_chip *chip, unsigned int offset)
return !!((val >> 4) & (1 << (offset % 4)));
}
-static void max310x_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+static int max310x_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct max310x_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[offset / 4].port;
max310x_port_update(port, MAX310X_GPIODATA_REG, 1 << (offset % 4),
value ? 1 << (offset % 4) : 0);
+
+ return 0;
}
static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
@@ -1411,7 +1414,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
s->gpio.direction_input = max310x_gpio_direction_input;
s->gpio.get = max310x_gpio_get;
s->gpio.direction_output= max310x_gpio_direction_output;
- s->gpio.set = max310x_gpio_set;
+ s->gpio.set_rv = max310x_gpio_set;
s->gpio.set_config = max310x_gpio_set_config;
s->gpio.base = -1;
s->gpio.ngpio = devtype->nr * 4;
diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c
index 059bea18dbab..4e47dca2c4ed 100644
--- a/drivers/tty/serial/milbeaut_usio.c
+++ b/drivers/tty/serial/milbeaut_usio.c
@@ -523,7 +523,10 @@ static int mlb_usio_probe(struct platform_device *pdev)
}
port->membase = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
-
+ if (!port->membase) {
+ ret = -ENOMEM;
+ goto failed;
+ }
ret = platform_get_irq_byname(pdev, "rx");
mlb_usio_irq[index][RX] = ret;
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 508e8c6f01d4..884fefbfd5a1 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -954,7 +954,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
__func__);
return 0;
}
- dma_sync_sg_for_device(port->dev, priv->sg_tx_p, nent, DMA_TO_DEVICE);
+ dma_sync_sg_for_device(port->dev, priv->sg_tx_p, num, DMA_TO_DEVICE);
priv->desc_tx = desc;
desc->callback = pch_dma_tx_complete;
desc->callback_param = priv;
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index a80ce7aaf309..32ec632fd080 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -11,6 +11,7 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -98,9 +99,17 @@
#define DMA_RX_BUF_SIZE 2048
+static DEFINE_IDA(port_ida);
+#define DOMAIN_IDX_POWER 0
+#define DOMAIN_IDX_PERF 1
+
struct qcom_geni_device_data {
bool console;
enum geni_se_xfer_mode mode;
+ struct dev_pm_domain_attach_data pd_data;
+ int (*resources_init)(struct uart_port *uport);
+ int (*set_rate)(struct uart_port *uport, unsigned int baud);
+ int (*power_state)(struct uart_port *uport, bool state);
};
struct qcom_geni_private_data {
@@ -138,6 +147,7 @@ struct qcom_geni_serial_port {
struct qcom_geni_private_data private_data;
const struct qcom_geni_device_data *dev_data;
+ struct dev_pm_domain_list *pd_list;
};
static const struct uart_ops qcom_geni_console_pops;
@@ -190,6 +200,33 @@ static struct qcom_geni_serial_port qcom_geni_console_port = {
},
};
+static const struct serial_rs485 qcom_geni_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND | SER_RS485_RTS_ON_SEND,
+};
+
+/**
+ * qcom_geni_set_rs485_mode - Set RTS pin state for RS485 mode
+ * @uport: UART port
+ * @flag: RS485 flag to determine RTS polarity
+ *
+ * Enables manual RTS control for RS485. Sets RTS to READY or NOT_READY
+ * based on the specified flag if RS485 mode is enabled.
+ */
+static void qcom_geni_set_rs485_mode(struct uart_port *uport, u32 flag)
+{
+ if (!(uport->rs485.flags & SER_RS485_ENABLED))
+ return;
+
+ u32 rfr = UART_MANUAL_RFR_EN;
+
+ if (uport->rs485.flags & flag)
+ rfr |= UART_RFR_NOT_READY;
+ else
+ rfr |= UART_RFR_READY;
+
+ writel(rfr, uport->membase + SE_UART_MANUAL_RFR);
+}
+
static int qcom_geni_serial_request_port(struct uart_port *uport)
{
struct platform_device *pdev = to_platform_device(uport->dev);
@@ -253,10 +290,24 @@ static struct qcom_geni_serial_port *get_port_from_line(int line, bool console)
struct qcom_geni_serial_port *port;
int nr_ports = console ? GENI_UART_CONS_PORTS : GENI_UART_PORTS;
- if (line < 0 || line >= nr_ports)
- return ERR_PTR(-ENXIO);
+ if (console) {
+ if (line < 0 || line >= nr_ports)
+ return ERR_PTR(-ENXIO);
+
+ port = &qcom_geni_console_port;
+ } else {
+ int max_alias_num = of_alias_get_highest_id("serial");
+
+ if (line < 0 || line >= nr_ports)
+ line = ida_alloc_range(&port_ida, max_alias_num + 1, nr_ports, GFP_KERNEL);
+ else
+ line = ida_alloc_range(&port_ida, line, nr_ports, GFP_KERNEL);
+
+ if (line < 0)
+ return ERR_PTR(-ENXIO);
- port = console ? &qcom_geni_console_port : &qcom_geni_uart_ports[line];
+ port = &qcom_geni_uart_ports[line];
+ }
return port;
}
@@ -648,6 +699,8 @@ static void qcom_geni_serial_start_tx_dma(struct uart_port *uport)
xmit_size = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail,
UART_XMIT_SIZE);
+ qcom_geni_set_rs485_mode(uport, SER_RS485_RTS_ON_SEND);
+
qcom_geni_serial_setup_tx(uport, xmit_size);
ret = geni_se_tx_dma_prep(&port->se, tail, xmit_size,
@@ -1055,8 +1108,10 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
}
if (dma) {
- if (dma_tx_status & TX_DMA_DONE)
+ if (dma_tx_status & TX_DMA_DONE) {
qcom_geni_serial_handle_tx_dma(uport);
+ qcom_geni_set_rs485_mode(uport, SER_RS485_RTS_AFTER_SEND);
+ }
if (dma_rx_status) {
if (dma_rx_status & RX_RESET_DONE)
@@ -1267,27 +1322,14 @@ static unsigned long get_clk_div_rate(struct clk *clk, unsigned int baud,
return ser_clk;
}
-static void qcom_geni_serial_set_termios(struct uart_port *uport,
- struct ktermios *termios,
- const struct ktermios *old)
+static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud)
{
- unsigned int baud;
- u32 bits_per_char;
- u32 tx_trans_cfg;
- u32 tx_parity_cfg;
- u32 rx_trans_cfg;
- u32 rx_parity_cfg;
- u32 stop_bit_len;
- unsigned int clk_div;
- u32 ser_clk_cfg;
struct qcom_geni_serial_port *port = to_dev_port(uport);
unsigned long clk_rate;
- u32 ver, sampling_rate;
unsigned int avg_bw_core;
- unsigned long timeout;
-
- /* baud rate */
- baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
+ unsigned int clk_div;
+ u32 ver, sampling_rate;
+ u32 ser_clk_cfg;
sampling_rate = UART_OVERSAMPLING;
/* Sampling rate is halved for IP versions >= 2.5 */
@@ -1301,7 +1343,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
dev_err(port->se.dev,
"Couldn't find suitable clock rate for %u\n",
baud * sampling_rate);
- return;
+ return -EINVAL;
}
dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n",
@@ -1323,6 +1365,69 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
port->se.icc_paths[CPU_TO_GENI].avg_bw = Bps_to_icc(baud);
geni_icc_set_bw(&port->se);
+ writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG);
+ writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG);
+ return 0;
+}
+
+static int geni_serial_set_level(struct uart_port *uport, unsigned int baud)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ struct device *perf_dev = port->pd_list->pd_devs[DOMAIN_IDX_PERF];
+
+ /*
+ * The performance protocol sets UART communication
+ * speeds by selecting different performance levels
+ * through the OPP framework.
+ *
+ * Supported perf levels for baudrates in firmware are below
+ * +---------------------+--------------------+
+ * | Perf level value | Baudrate values |
+ * +---------------------+--------------------+
+ * | 300 | 300 |
+ * | 1200 | 1200 |
+ * | 2400 | 2400 |
+ * | 4800 | 4800 |
+ * | 9600 | 9600 |
+ * | 19200 | 19200 |
+ * | 38400 | 38400 |
+ * | 57600 | 57600 |
+ * | 115200 | 115200 |
+ * | 230400 | 230400 |
+ * | 460800 | 460800 |
+ * | 921600 | 921600 |
+ * | 2000000 | 2000000 |
+ * | 3000000 | 3000000 |
+ * | 3200000 | 3200000 |
+ * | 4000000 | 4000000 |
+ * +---------------------+--------------------+
+ */
+
+ return dev_pm_opp_set_level(perf_dev, baud);
+}
+
+static void qcom_geni_serial_set_termios(struct uart_port *uport,
+ struct ktermios *termios,
+ const struct ktermios *old)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ unsigned int baud;
+ unsigned long timeout;
+ u32 bits_per_char;
+ u32 tx_trans_cfg;
+ u32 tx_parity_cfg;
+ u32 rx_trans_cfg;
+ u32 rx_parity_cfg;
+ u32 stop_bit_len;
+ int ret = 0;
+
+ /* baud rate */
+ baud = uart_get_baud_rate(uport, termios, old, 300, 8000000);
+
+ ret = port->dev_data->set_rate(uport, baud);
+ if (ret)
+ return;
+
/* parity */
tx_trans_cfg = readl(uport->membase + SE_UART_TX_TRANS_CFG);
tx_parity_cfg = readl(uport->membase + SE_UART_TX_PARITY_CFG);
@@ -1390,8 +1495,6 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
writel(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN);
writel(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN);
writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN);
- writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG);
- writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG);
}
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
@@ -1572,26 +1675,130 @@ static struct uart_driver qcom_geni_uart_driver = {
.nr = GENI_UART_PORTS,
};
+static int geni_serial_resources_on(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ int ret;
+
+ ret = geni_icc_enable(&port->se);
+ if (ret)
+ return ret;
+
+ ret = geni_se_resources_on(&port->se);
+ if (ret) {
+ geni_icc_disable(&port->se);
+ return ret;
+ }
+
+ if (port->clk_rate)
+ dev_pm_opp_set_rate(uport->dev, port->clk_rate);
+
+ return 0;
+}
+
+static int geni_serial_resources_off(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ int ret;
+
+ dev_pm_opp_set_rate(uport->dev, 0);
+ ret = geni_se_resources_off(&port->se);
+ if (ret)
+ return ret;
+
+ geni_icc_disable(&port->se);
+
+ return 0;
+}
+
+static int geni_serial_resource_state(struct uart_port *uport, bool power_on)
+{
+ return power_on ? geni_serial_resources_on(uport) : geni_serial_resources_off(uport);
+}
+
+static int geni_serial_pwr_init(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ int ret;
+
+ ret = dev_pm_domain_attach_list(port->se.dev,
+ &port->dev_data->pd_data, &port->pd_list);
+ if (ret <= 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int geni_serial_resource_init(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ int ret;
+
+ port->se.clk = devm_clk_get(port->se.dev, "se");
+ if (IS_ERR(port->se.clk)) {
+ ret = PTR_ERR(port->se.clk);
+ dev_err(port->se.dev, "Err getting SE Core clk %d\n", ret);
+ return ret;
+ }
+
+ ret = geni_icc_get(&port->se, NULL);
+ if (ret)
+ return ret;
+
+ port->se.icc_paths[GENI_TO_CORE].avg_bw = GENI_DEFAULT_BW;
+ port->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW;
+
+ /* Set BW for register access */
+ ret = geni_icc_set_bw(&port->se);
+ if (ret)
+ return ret;
+
+ ret = devm_pm_opp_set_clkname(port->se.dev, "se");
+ if (ret)
+ return ret;
+
+ /* OPP table is optional */
+ ret = devm_pm_opp_of_add_table(port->se.dev);
+ if (ret && ret != -ENODEV) {
+ dev_err(port->se.dev, "invalid OPP table in device tree\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static void qcom_geni_serial_pm(struct uart_port *uport,
unsigned int new_state, unsigned int old_state)
{
- struct qcom_geni_serial_port *port = to_dev_port(uport);
/* If we've never been called, treat it as off */
if (old_state == UART_PM_STATE_UNDEFINED)
old_state = UART_PM_STATE_OFF;
- if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF) {
- geni_icc_enable(&port->se);
- if (port->clk_rate)
- dev_pm_opp_set_rate(uport->dev, port->clk_rate);
- geni_se_resources_on(&port->se);
- } else if (new_state == UART_PM_STATE_OFF &&
- old_state == UART_PM_STATE_ON) {
- geni_se_resources_off(&port->se);
- dev_pm_opp_set_rate(uport->dev, 0);
- geni_icc_disable(&port->se);
- }
+ if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF)
+ pm_runtime_resume_and_get(uport->dev);
+ else if (new_state == UART_PM_STATE_OFF &&
+ old_state == UART_PM_STATE_ON)
+ pm_runtime_put_sync(uport->dev);
+
+}
+
+/**
+ * qcom_geni_rs485_config - Configure RS485 settings for the UART port
+ * @uport: Pointer to the UART port structure
+ * @termios: Pointer to the termios structure
+ * @rs485: Pointer to the RS485 configuration structure
+ * This function configures the RTS (Request to Send) pin behavior for RS485 mode.
+ * When RS485 mode is enabled, the RTS pin is kept in default ACTIVE HIGH state.
+ * Return: Always returns 0.
+ */
+
+static int qcom_geni_rs485_config(struct uart_port *uport,
+ struct ktermios *termios, struct serial_rs485 *rs485)
+{
+ qcom_geni_set_rs485_mode(uport, SER_RS485_ENABLED);
+
+ return 0;
}
static const struct uart_ops qcom_geni_console_pops = {
@@ -1674,18 +1881,21 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
port->dev_data = data;
port->se.dev = &pdev->dev;
port->se.wrapper = dev_get_drvdata(pdev->dev.parent);
- port->se.clk = devm_clk_get(&pdev->dev, "se");
- if (IS_ERR(port->se.clk)) {
- ret = PTR_ERR(port->se.clk);
- dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret);
+
+ ret = port->dev_data->resources_init(uport);
+ if (ret)
return ret;
- }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EINVAL;
+ if (!res) {
+ ret = -EINVAL;
+ goto error;
+ }
+
uport->mapbase = res->start;
+ uport->rs485_config = qcom_geni_rs485_config;
+ uport->rs485_supported = qcom_geni_rs485_supported;
port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
@@ -1693,30 +1903,26 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
if (!data->console) {
port->rx_buf = devm_kzalloc(uport->dev,
DMA_RX_BUF_SIZE, GFP_KERNEL);
- if (!port->rx_buf)
- return -ENOMEM;
+ if (!port->rx_buf) {
+ ret = -ENOMEM;
+ goto error;
+ }
}
- ret = geni_icc_get(&port->se, NULL);
- if (ret)
- return ret;
- port->se.icc_paths[GENI_TO_CORE].avg_bw = GENI_DEFAULT_BW;
- port->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW;
-
- /* Set BW for register access */
- ret = geni_icc_set_bw(&port->se);
- if (ret)
- return ret;
-
port->name = devm_kasprintf(uport->dev, GFP_KERNEL,
"qcom_geni_serial_%s%d",
uart_console(uport) ? "console" : "uart", uport->line);
- if (!port->name)
- return -ENOMEM;
+ if (!port->name) {
+ ret = -ENOMEM;
+ goto error;
+ }
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
+ if (irq < 0) {
+ ret = irq;
+ goto error;
+ }
+
uport->irq = irq;
uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE);
@@ -1729,16 +1935,6 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
if (of_property_read_bool(pdev->dev.of_node, "cts-rts-swap"))
port->cts_rts_swap = true;
- ret = devm_pm_opp_set_clkname(&pdev->dev, "se");
- if (ret)
- return ret;
- /* OPP table is optional */
- ret = devm_pm_opp_of_add_table(&pdev->dev);
- if (ret && ret != -ENODEV) {
- dev_err(&pdev->dev, "invalid OPP table in device tree\n");
- return ret;
- }
-
port->private_data.drv = drv;
uport->private_data = &port->private_data;
platform_set_drvdata(pdev, port);
@@ -1748,35 +1944,73 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
IRQF_TRIGGER_HIGH, port->name, uport);
if (ret) {
dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret);
- return ret;
+ goto error;
}
- ret = uart_add_one_port(drv, uport);
+ ret = uart_get_rs485_mode(uport);
if (ret)
return ret;
+ devm_pm_runtime_enable(port->se.dev);
+
+ ret = uart_add_one_port(drv, uport);
+ if (ret)
+ goto error;
+
if (port->wakeup_irq > 0) {
device_init_wakeup(&pdev->dev, true);
ret = dev_pm_set_dedicated_wake_irq(&pdev->dev,
port->wakeup_irq);
if (ret) {
device_init_wakeup(&pdev->dev, false);
+ ida_free(&port_ida, uport->line);
uart_remove_one_port(drv, uport);
- return ret;
+ goto error;
}
}
return 0;
+
+error:
+ dev_pm_domain_detach_list(port->pd_list);
+ return ret;
}
static void qcom_geni_serial_remove(struct platform_device *pdev)
{
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
+ struct uart_port *uport = &port->uport;
struct uart_driver *drv = port->private_data.drv;
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
+ ida_free(&port_ida, uport->line);
uart_remove_one_port(drv, &port->uport);
+ dev_pm_domain_detach_list(port->pd_list);
+}
+
+static int __maybe_unused qcom_geni_serial_runtime_suspend(struct device *dev)
+{
+ struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
+ struct uart_port *uport = &port->uport;
+ int ret = 0;
+
+ if (port->dev_data->power_state)
+ ret = port->dev_data->power_state(uport, false);
+
+ return ret;
+}
+
+static int __maybe_unused qcom_geni_serial_runtime_resume(struct device *dev)
+{
+ struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
+ struct uart_port *uport = &port->uport;
+ int ret = 0;
+
+ if (port->dev_data->power_state)
+ ret = port->dev_data->power_state(uport, true);
+
+ return ret;
}
static int qcom_geni_serial_suspend(struct device *dev)
@@ -1814,14 +2048,46 @@ static int qcom_geni_serial_resume(struct device *dev)
static const struct qcom_geni_device_data qcom_geni_console_data = {
.console = true,
.mode = GENI_SE_FIFO,
+ .resources_init = geni_serial_resource_init,
+ .set_rate = geni_serial_set_rate,
+ .power_state = geni_serial_resource_state,
};
static const struct qcom_geni_device_data qcom_geni_uart_data = {
.console = false,
.mode = GENI_SE_DMA,
+ .resources_init = geni_serial_resource_init,
+ .set_rate = geni_serial_set_rate,
+ .power_state = geni_serial_resource_state,
+};
+
+static const struct qcom_geni_device_data sa8255p_qcom_geni_console_data = {
+ .console = true,
+ .mode = GENI_SE_FIFO,
+ .pd_data = {
+ .pd_flags = PD_FLAG_DEV_LINK_ON,
+ .pd_names = (const char*[]) { "power", "perf" },
+ .num_pd_names = 2,
+ },
+ .resources_init = geni_serial_pwr_init,
+ .set_rate = geni_serial_set_level,
+};
+
+static const struct qcom_geni_device_data sa8255p_qcom_geni_uart_data = {
+ .console = false,
+ .mode = GENI_SE_DMA,
+ .pd_data = {
+ .pd_flags = PD_FLAG_DEV_LINK_ON,
+ .pd_names = (const char*[]) { "power", "perf" },
+ .num_pd_names = 2,
+ },
+ .resources_init = geni_serial_pwr_init,
+ .set_rate = geni_serial_set_level,
};
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
+ SET_RUNTIME_PM_OPS(qcom_geni_serial_runtime_suspend,
+ qcom_geni_serial_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_suspend, qcom_geni_serial_resume)
};
@@ -1831,9 +2097,17 @@ static const struct of_device_id qcom_geni_serial_match_table[] = {
.data = &qcom_geni_console_data,
},
{
+ .compatible = "qcom,sa8255p-geni-debug-uart",
+ .data = &sa8255p_qcom_geni_console_data,
+ },
+ {
.compatible = "qcom,geni-uart",
.data = &qcom_geni_uart_data,
},
+ {
+ .compatible = "qcom,sa8255p-geni-uart",
+ .data = &sa8255p_qcom_geni_uart_data,
+ },
{}
};
MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table);
diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c
new file mode 100644
index 000000000000..b3c48dc1e07d
--- /dev/null
+++ b/drivers/tty/serial/rsci.c
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 Renesas Electronics Corp.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/serial_core.h>
+#include <linux/serial_sci.h>
+#include <linux/tty_flip.h>
+#include "rsci.h"
+
+MODULE_IMPORT_NS("SH_SCI");
+
+/* RSCI registers */
+#define RDR 0x00
+#define TDR 0x04
+#define CCR0 0x08
+#define CCR1 0x0C
+#define CCR2 0x10
+#define CCR3 0x14
+#define CCR4 0x18
+#define FCR 0x24
+#define DCR 0x30
+#define CSR 0x48
+#define FRSR 0x50
+#define FTSR 0x54
+#define CFCLR 0x68
+#define FFCLR 0x70
+
+/* RDR (Receive Data Register) */
+#define RDR_FFER BIT(12) /* FIFO Framing Error */
+#define RDR_FPER BIT(11) /* FIFO Parity Error */
+#define RDR_RDAT_MSK GENMASK(8, 0)
+
+/* TDR (Transmit Data Register) */
+#define TDR_MPBT BIT(9) /* Multiprocessor Transfer */
+#define TDR_TDAT_9BIT_LSHIFT 0
+#define TDR_TDAT_9BIT_VAL 0x1FF
+#define TDR_TDAT_9BIT_MSK (TDR_TDAT_9BIT_VAL << TDR_TDAT_9BIT_LSHIFT)
+
+/* CCR0 (Common Control Register 0) */
+#define CCR0_SSE BIT(24) /* SSn# Pin Function Enable */
+#define CCR0_TEIE BIT(21) /* Transmit End Interrupt Enable */
+#define CCR0_TIE BIT(20) /* Transmit Interrupt Enable */
+#define CCR0_RIE BIT(16) /* Receive Interrupt Enable */
+#define CCR0_IDSEL BIT(10) /* ID Frame Select */
+#define CCR0_DCME BIT(9) /* Data Compare Match Enable */
+#define CCR0_MPIE BIT(8) /* Multiprocessor Interrupt Enable */
+#define CCR0_TE BIT(4) /* Transmit Enable */
+#define CCR0_RE BIT(0) /* Receive Enable */
+
+/* CCR1 (Common Control Register 1) */
+#define CCR1_NFEN BIT(28) /* Digital Noise Filter Function */
+#define CCR1_SHARPS BIT(20) /* Half -duplex Communication Select */
+#define CCR1_SPLP BIT(16) /* Loopback Control */
+#define CCR1_RINV BIT(13) /* RxD invert */
+#define CCR1_TINV BIT(12) /* TxD invert */
+#define CCR1_PM BIT(9) /* Parity Mode */
+#define CCR1_PE BIT(8) /* Parity Enable */
+#define CCR1_SPB2IO BIT(5) /* Serial Port Break I/O */
+#define CCR1_SPB2DT BIT(4) /* Serial Port Break Data Select */
+#define CCR1_CTSPEN BIT(1) /* CTS External Pin Enable */
+#define CCR1_CTSE BIT(0) /* CTS Enable */
+
+/* FCR (FIFO Control Register) */
+#define FCR_RFRST BIT(23) /* Receive FIFO Data Register Reset */
+#define FCR_TFRST BIT(15) /* Transmit FIFO Data Register Reset */
+#define FCR_DRES BIT(0) /* Incoming Data Ready Error Select */
+#define FCR_RTRG4_0 GENMASK(20, 16)
+#define FCR_TTRG GENMASK(12, 8)
+
+/* CSR (Common Status Register) */
+#define CSR_RDRF BIT(31) /* Receive Data Full */
+#define CSR_TEND BIT(30) /* Transmit End Flag */
+#define CSR_TDRE BIT(29) /* Transmit Data Empty */
+#define CSR_FER BIT(28) /* Framing Error */
+#define CSR_PER BIT(27) /* Parity Error */
+#define CSR_MFF BIT(26) /* Mode Fault Error */
+#define CSR_ORER BIT(24) /* Overrun Error */
+#define CSR_DFER BIT(18) /* Data Compare Match Framing Error */
+#define CSR_DPER BIT(17) /* Data Compare Match Parity Error */
+#define CSR_DCMF BIT(16) /* Data Compare Match */
+#define CSR_RXDMON BIT(15) /* Serial Input Data Monitor */
+#define CSR_ERS BIT(4) /* Error Signal Status */
+
+#define SCxSR_ERRORS(port) (to_sci_port(port)->params->error_mask)
+#define SCxSR_ERROR_CLEAR(port) (to_sci_port(port)->params->error_clear)
+
+#define RSCI_DEFAULT_ERROR_MASK (CSR_PER | CSR_FER)
+
+#define RSCI_RDxF_CLEAR (CFCLR_RDRFC)
+#define RSCI_ERROR_CLEAR (CFCLR_PERC | CFCLR_FERC)
+#define RSCI_TDxE_CLEAR (CFCLR_TDREC)
+#define RSCI_BREAK_CLEAR (CFCLR_PERC | CFCLR_FERC | CFCLR_ORERC)
+
+/* FRSR (FIFO Receive Status Register) */
+#define FRSR_R5_0 GENMASK(13, 8) /* Receive FIFO Data Count */
+#define FRSR_DR BIT(0) /* Receive Data Ready */
+
+/* CFCLR (Common Flag CLear Register) */
+#define CFCLR_RDRFC BIT(31) /* RDRF Clear */
+#define CFCLR_TDREC BIT(29) /* TDRE Clear */
+#define CFCLR_FERC BIT(28) /* FER Clear */
+#define CFCLR_PERC BIT(27) /* PER Clear */
+#define CFCLR_MFFC BIT(26) /* MFF Clear */
+#define CFCLR_ORERC BIT(24) /* ORER Clear */
+#define CFCLR_DFERC BIT(18) /* DFER Clear */
+#define CFCLR_DPERC BIT(17) /* DPER Clear */
+#define CFCLR_DCMFC BIT(16) /* DCMF Clear */
+#define CFCLR_ERSC BIT(4) /* ERS Clear */
+#define CFCLR_CLRFLAG (CFCLR_RDRFC | CFCLR_FERC | CFCLR_PERC | \
+ CFCLR_MFFC | CFCLR_ORERC | CFCLR_DFERC | \
+ CFCLR_DPERC | CFCLR_DCMFC | CFCLR_ERSC)
+
+/* FFCLR (FIFO Flag CLear Register) */
+#define FFCLR_DRC BIT(0) /* DR Clear */
+
+#define DCR_DEPOL BIT(0)
+
+static u32 rsci_serial_in(struct uart_port *p, int offset)
+{
+ return readl(p->membase + offset);
+}
+
+static void rsci_serial_out(struct uart_port *p, int offset, int value)
+{
+ writel(value, p->membase + offset);
+}
+
+static void rsci_clear_DRxC(struct uart_port *port)
+{
+ rsci_serial_out(port, CFCLR, CFCLR_RDRFC);
+ rsci_serial_out(port, FFCLR, FFCLR_DRC);
+}
+
+static void rsci_clear_SCxSR(struct uart_port *port, unsigned int mask)
+{
+ rsci_serial_out(port, CFCLR, mask);
+}
+
+static void rsci_start_rx(struct uart_port *port)
+{
+ unsigned int ctrl;
+
+ ctrl = rsci_serial_in(port, CCR0);
+ ctrl |= CCR0_RIE;
+ rsci_serial_out(port, CCR0, ctrl);
+}
+
+static void rsci_set_termios(struct uart_port *port, struct ktermios *termios,
+ const struct ktermios *old)
+{
+ struct sci_port *s = to_sci_port(port);
+ unsigned long flags;
+
+ sci_port_enable(s);
+ uart_port_lock_irqsave(port, &flags);
+
+ /* For now, only RX enabling is supported */
+ if (termios->c_cflag & CREAD)
+ rsci_start_rx(port);
+
+ uart_port_unlock_irqrestore(port, flags);
+ sci_port_disable(s);
+}
+
+static int rsci_txfill(struct uart_port *port)
+{
+ return rsci_serial_in(port, FTSR);
+}
+
+static int rsci_rxfill(struct uart_port *port)
+{
+ u32 val = rsci_serial_in(port, FRSR);
+
+ return FIELD_GET(FRSR_R5_0, val);
+}
+
+static unsigned int rsci_tx_empty(struct uart_port *port)
+{
+ unsigned int status = rsci_serial_in(port, CSR);
+ unsigned int in_tx_fifo = rsci_txfill(port);
+
+ return (status & CSR_TEND) && !in_tx_fifo ? TIOCSER_TEMT : 0;
+}
+
+static void rsci_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /* Not supported yet */
+}
+
+static unsigned int rsci_get_mctrl(struct uart_port *port)
+{
+ /* Not supported yet */
+ return 0;
+}
+
+static void rsci_clear_CFC(struct uart_port *port, unsigned int mask)
+{
+ rsci_serial_out(port, CFCLR, mask);
+}
+
+static void rsci_start_tx(struct uart_port *port)
+{
+ struct sci_port *sp = to_sci_port(port);
+ u32 ctrl;
+
+ if (sp->chan_tx)
+ return;
+
+ /*
+ * TE (Transmit Enable) must be set after setting TIE
+ * (Transmit Interrupt Enable) or in the same instruction
+ * to start the transmit process.
+ */
+ ctrl = rsci_serial_in(port, CCR0);
+ ctrl |= CCR0_TIE | CCR0_TE;
+ rsci_serial_out(port, CCR0, ctrl);
+}
+
+static void rsci_stop_tx(struct uart_port *port)
+{
+ u32 ctrl;
+
+ ctrl = rsci_serial_in(port, CCR0);
+ ctrl &= ~CCR0_TIE;
+ rsci_serial_out(port, CCR0, ctrl);
+}
+
+static void rsci_stop_rx(struct uart_port *port)
+{
+ u32 ctrl;
+
+ ctrl = rsci_serial_in(port, CCR0);
+ ctrl &= ~CCR0_RIE;
+ rsci_serial_out(port, CCR0, ctrl);
+}
+
+static int rsci_txroom(struct uart_port *port)
+{
+ return port->fifosize - rsci_txfill(port);
+}
+
+static void rsci_transmit_chars(struct uart_port *port)
+{
+ unsigned int stopped = uart_tx_stopped(port);
+ struct tty_port *tport = &port->state->port;
+ u32 status, ctrl;
+ int count;
+
+ status = rsci_serial_in(port, CSR);
+ if (!(status & CSR_TDRE)) {
+ ctrl = rsci_serial_in(port, CCR0);
+ if (kfifo_is_empty(&tport->xmit_fifo))
+ ctrl &= ~CCR0_TIE;
+ else
+ ctrl |= CCR0_TIE;
+ rsci_serial_out(port, CCR0, ctrl);
+ return;
+ }
+
+ count = rsci_txroom(port);
+
+ do {
+ unsigned char c;
+
+ if (port->x_char) {
+ c = port->x_char;
+ port->x_char = 0;
+ } else if (stopped || !kfifo_get(&tport->xmit_fifo, &c)) {
+ break;
+ }
+
+ rsci_clear_CFC(port, CFCLR_TDREC);
+ rsci_serial_out(port, TDR, c);
+
+ port->icount.tx++;
+ } while (--count > 0);
+
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (kfifo_is_empty(&tport->xmit_fifo)) {
+ ctrl = rsci_serial_in(port, CCR0);
+ ctrl &= ~CCR0_TIE;
+ ctrl |= CCR0_TEIE;
+ rsci_serial_out(port, CCR0, ctrl);
+ }
+}
+
+static void rsci_receive_chars(struct uart_port *port)
+{
+ struct tty_port *tport = &port->state->port;
+ u32 rdat, status, frsr_status = 0;
+ int i, count, copied = 0;
+ unsigned char flag;
+
+ status = rsci_serial_in(port, CSR);
+ frsr_status = rsci_serial_in(port, FRSR);
+
+ if (!(status & CSR_RDRF) && !(frsr_status & FRSR_DR))
+ return;
+
+ while (1) {
+ /* Don't copy more bytes than there is room for in the buffer */
+ count = tty_buffer_request_room(tport, rsci_rxfill(port));
+
+ /* If for any reason we can't copy more data, we're done! */
+ if (count == 0)
+ break;
+
+ for (i = 0; i < count; i++) {
+ char c;
+
+ rdat = rsci_serial_in(port, RDR);
+ /* 9-bits data is not supported yet */
+ c = rdat & RDR_RDAT_MSK;
+
+ if (uart_handle_sysrq_char(port, c)) {
+ count--;
+ i--;
+ continue;
+ }
+
+ /* Store data and status.
+ * Non FIFO mode is not supported
+ */
+ if (rdat & RDR_FFER) {
+ flag = TTY_FRAME;
+ port->icount.frame++;
+ } else if (rdat & RDR_FPER) {
+ flag = TTY_PARITY;
+ port->icount.parity++;
+ } else {
+ flag = TTY_NORMAL;
+ }
+
+ tty_insert_flip_char(tport, c, flag);
+ }
+
+ rsci_serial_in(port, CSR); /* dummy read */
+ rsci_clear_DRxC(port);
+
+ copied += count;
+ port->icount.rx += count;
+ }
+
+ if (copied) {
+ /* Tell the rest of the system the news. New characters! */
+ tty_flip_buffer_push(tport);
+ } else {
+ /* TTY buffers full; read from RX reg to prevent lockup */
+ rsci_serial_in(port, RDR);
+ rsci_serial_in(port, CSR); /* dummy read */
+ rsci_clear_DRxC(port);
+ }
+}
+
+static void rsci_poll_put_char(struct uart_port *port, unsigned char c)
+{
+ u32 status;
+ int ret;
+
+ ret = readl_relaxed_poll_timeout_atomic(port->membase + CSR, status,
+ (status & CSR_TDRE), 100,
+ USEC_PER_SEC);
+ if (ret != 0) {
+ dev_err(port->dev,
+ "Error while sending data in UART TX : %d\n", ret);
+ goto done;
+ }
+ rsci_serial_out(port, TDR, c);
+done:
+ rsci_clear_SCxSR(port, CFCLR_TDREC);
+}
+
+static void rsci_prepare_console_write(struct uart_port *port, u32 ctrl)
+{
+ struct sci_port *s = to_sci_port(port);
+ u32 ctrl_temp =
+ s->params->param_bits->rxtx_enable | CCR0_TIE |
+ s->hscif_tot;
+ rsci_serial_out(port, CCR0, ctrl_temp);
+}
+
+static const char *rsci_type(struct uart_port *port)
+{
+ return "rsci";
+}
+
+static size_t rsci_suspend_regs_size(void)
+{
+ return 0;
+}
+
+static void rsci_shutdown_complete(struct uart_port *port)
+{
+ /*
+ * Stop RX and TX, disable related interrupts, keep clock source
+ */
+ rsci_serial_out(port, CCR0, 0);
+}
+
+static const struct sci_common_regs rsci_common_regs = {
+ .status = CSR,
+ .control = CCR0,
+};
+
+static const struct sci_port_params_bits rsci_port_param_bits = {
+ .rxtx_enable = CCR0_RE | CCR0_TE,
+ .te_clear = CCR0_TE | CCR0_TEIE,
+ .poll_sent_bits = CSR_TDRE | CSR_TEND,
+};
+
+static const struct sci_port_params rsci_port_params = {
+ .fifosize = 16,
+ .overrun_reg = CSR,
+ .overrun_mask = CSR_ORER,
+ .sampling_rate_mask = SCI_SR(32),
+ .error_mask = RSCI_DEFAULT_ERROR_MASK,
+ .error_clear = RSCI_ERROR_CLEAR,
+ .param_bits = &rsci_port_param_bits,
+ .common_regs = &rsci_common_regs,
+};
+
+static const struct uart_ops rsci_uart_ops = {
+ .tx_empty = rsci_tx_empty,
+ .set_mctrl = rsci_set_mctrl,
+ .get_mctrl = rsci_get_mctrl,
+ .start_tx = rsci_start_tx,
+ .stop_tx = rsci_stop_tx,
+ .stop_rx = rsci_stop_rx,
+ .startup = sci_startup,
+ .shutdown = sci_shutdown,
+ .set_termios = rsci_set_termios,
+ .pm = sci_pm,
+ .type = rsci_type,
+ .release_port = sci_release_port,
+ .request_port = sci_request_port,
+ .config_port = sci_config_port,
+ .verify_port = sci_verify_port,
+};
+
+static const struct sci_port_ops rsci_port_ops = {
+ .read_reg = rsci_serial_in,
+ .write_reg = rsci_serial_out,
+ .clear_SCxSR = rsci_clear_SCxSR,
+ .transmit_chars = rsci_transmit_chars,
+ .receive_chars = rsci_receive_chars,
+ .poll_put_char = rsci_poll_put_char,
+ .prepare_console_write = rsci_prepare_console_write,
+ .suspend_regs_size = rsci_suspend_regs_size,
+ .shutdown_complete = rsci_shutdown_complete,
+};
+
+struct sci_of_data of_sci_rsci_data = {
+ .type = SCI_PORT_RSCI,
+ .ops = &rsci_port_ops,
+ .uart_ops = &rsci_uart_ops,
+ .params = &rsci_port_params,
+};
+
+#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
+
+static int __init rsci_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return scix_early_console_setup(device, &of_sci_rsci_data);
+}
+
+OF_EARLYCON_DECLARE(rsci, "renesas,r9a09g077-rsci", rsci_early_console_setup);
+
+#endif /* CONFIG_SERIAL_SH_SCI_EARLYCON */
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RSCI serial driver");
diff --git a/drivers/tty/serial/rsci.h b/drivers/tty/serial/rsci.h
new file mode 100644
index 000000000000..2af3f28b465a
--- /dev/null
+++ b/drivers/tty/serial/rsci.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __RSCI_H__
+#define __RSCI_H__
+
+#include "sh-sci-common.h"
+
+extern struct sci_of_data of_sci_rsci_data;
+
+#endif /* __RSCI_H__ */
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
index 8587ebbe1073..72b1bb76415c 100644
--- a/drivers/tty/serial/sa1100.c
+++ b/drivers/tty/serial/sa1100.c
@@ -111,7 +111,7 @@ static void sa1100_mctrl_check(struct sa1100_port *sport)
*/
static void sa1100_timeout(struct timer_list *t)
{
- struct sa1100_port *sport = from_timer(sport, t, timer);
+ struct sa1100_port *sport = timer_container_of(sport, t, timer);
unsigned long flags;
if (sport->port.state) {
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 210fff7164c1..2fb58c626daf 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -52,7 +52,7 @@
#define S3C24XX_SERIAL_MINOR 64
#ifdef CONFIG_ARM64
-#define UART_NR 12
+#define UART_NR 18
#else
#define UART_NR CONFIG_SERIAL_SAMSUNG_UARTS
#endif
@@ -190,6 +190,8 @@ static void wr_reg(const struct uart_port *port, u32 reg, u32 val)
case UPIO_MEM32:
writel_relaxed(val, portaddr(port, reg));
break;
+ default:
+ break;
}
}
@@ -2713,6 +2715,8 @@ static void wr_reg_barrier(const struct uart_port *port, u32 reg, u32 val)
case UPIO_MEM32:
writel(val, portaddr(port, reg));
break;
+ default:
+ break;
}
}
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 560f45ed19ae..5ea8aadb6e69 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -1333,13 +1333,16 @@ static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset)
return !!(val & BIT(offset));
}
-static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+static int sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int val)
{
struct sc16is7xx_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[0].port;
sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset),
val ? BIT(offset) : 0);
+
+ return 0;
}
static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip,
@@ -1422,7 +1425,7 @@ static int sc16is7xx_setup_gpio_chip(struct sc16is7xx_port *s)
s->gpio.direction_input = sc16is7xx_gpio_direction_input;
s->gpio.get = sc16is7xx_gpio_get;
s->gpio.direction_output = sc16is7xx_gpio_direction_output;
- s->gpio.set = sc16is7xx_gpio_set;
+ s->gpio.set_rv = sc16is7xx_gpio_set;
s->gpio.base = -1;
s->gpio.ngpio = s->devtype->nr_gpio;
s->gpio.can_sleep = 1;
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index 553e3c1321ca..4ceca11ce600 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -500,7 +500,7 @@ static void sccnxp_handle_events(struct sccnxp_port *s)
static void sccnxp_timer(struct timer_list *t)
{
- struct sccnxp_port *s = from_timer(s, t, timer);
+ struct sccnxp_port *s = timer_container_of(s, t, timer);
unsigned long flags;
spin_lock_irqsave(&s->lock, flags);
diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c
index 5d1677f1b651..22749ab0428a 100644
--- a/drivers/tty/serial/serial_base_bus.c
+++ b/drivers/tty/serial/serial_base_bus.c
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -72,6 +73,7 @@ static int serial_base_device_init(struct uart_port *port,
dev->parent = parent_dev;
dev->bus = &serial_base_bus_type;
dev->release = release;
+ device_set_of_node_from_dev(dev, parent_dev);
if (!serial_base_initialized) {
dev_dbg(port->dev, "uart_add_one_port() called before arch_initcall()?\n");
@@ -92,6 +94,7 @@ static void serial_base_ctrl_release(struct device *dev)
{
struct serial_ctrl_device *ctrl_dev = to_serial_base_ctrl_device(dev);
+ of_node_put(dev->of_node);
kfree(ctrl_dev);
}
@@ -139,6 +142,7 @@ static void serial_base_port_release(struct device *dev)
{
struct serial_port_device *port_dev = to_serial_base_port_device(dev);
+ of_node_put(dev->of_node);
kfree(port_dev);
}
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 88669972d9a0..86d404d649a3 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -75,22 +75,23 @@ static inline void uart_port_deref(struct uart_port *uport)
wake_up(&uport->state->remove_wait);
}
-#define uart_port_lock(state, flags) \
- ({ \
- struct uart_port *__uport = uart_port_ref(state); \
- if (__uport) \
- uart_port_lock_irqsave(__uport, &flags); \
- __uport; \
- })
-
-#define uart_port_unlock(uport, flags) \
- ({ \
- struct uart_port *__uport = uport; \
- if (__uport) { \
- uart_port_unlock_irqrestore(__uport, flags); \
- uart_port_deref(__uport); \
- } \
- })
+static inline struct uart_port *uart_port_ref_lock(struct uart_state *state, unsigned long *flags)
+{
+ struct uart_port *uport = uart_port_ref(state);
+
+ if (uport)
+ uart_port_lock_irqsave(uport, flags);
+
+ return uport;
+}
+
+static inline void uart_port_unlock_deref(struct uart_port *uport, unsigned long flags)
+{
+ if (uport) {
+ uart_port_unlock_irqrestore(uport, flags);
+ uart_port_deref(uport);
+ }
+}
static inline struct uart_port *uart_port_check(struct uart_state *state)
{
@@ -127,10 +128,10 @@ static void uart_stop(struct tty_struct *tty)
struct uart_port *port;
unsigned long flags;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (port)
port->ops->stop_tx(port);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
}
static void __uart_start(struct uart_state *state)
@@ -168,9 +169,9 @@ static void uart_start(struct tty_struct *tty)
struct uart_port *port;
unsigned long flags;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
__uart_start(state);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
}
static void
@@ -258,14 +259,14 @@ static int uart_alloc_xmit_buf(struct tty_port *port)
if (!page)
return -ENOMEM;
- uport = uart_port_lock(state, flags);
+ uport = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
state->port.xmit_buf = (unsigned char *)page;
kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf,
PAGE_SIZE);
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
} else {
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
/*
* Do not free() the page under the port lock, see
* uart_free_xmit_buf().
@@ -289,11 +290,11 @@ static void uart_free_xmit_buf(struct tty_port *port)
* console driver may need to allocate/free a debug object, which
* can end up in printk() recursion.
*/
- uport = uart_port_lock(state, flags);
+ uport = uart_port_ref_lock(state, &flags);
xmit_buf = port->xmit_buf;
port->xmit_buf = NULL;
INIT_KFIFO(port->xmit_fifo);
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
free_page((unsigned long)xmit_buf);
}
@@ -592,15 +593,15 @@ static int uart_put_char(struct tty_struct *tty, u8 c)
unsigned long flags;
int ret = 0;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return 0;
}
if (port)
ret = kfifo_put(&state->port.xmit_fifo, c);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -623,9 +624,9 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
if (WARN_ON(!state))
return -EL3HLT;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return 0;
}
@@ -633,7 +634,7 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
ret = kfifo_in(&state->port.xmit_fifo, buf, count);
__uart_start(state);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -644,9 +645,9 @@ static unsigned int uart_write_room(struct tty_struct *tty)
unsigned long flags;
unsigned int ret;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
ret = kfifo_avail(&state->port.xmit_fifo);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -657,9 +658,9 @@ static unsigned int uart_chars_in_buffer(struct tty_struct *tty)
unsigned long flags;
unsigned int ret;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
ret = kfifo_len(&state->port.xmit_fifo);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -678,13 +679,13 @@ static void uart_flush_buffer(struct tty_struct *tty)
pr_debug("uart_flush_buffer(%d) called\n", tty->index);
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!port)
return;
kfifo_reset(&state->port.xmit_fifo);
if (port->ops->flush_buffer)
port->ops->flush_buffer(port);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
tty_port_tty_wakeup(&state->port);
}
@@ -1275,14 +1276,13 @@ static int uart_get_icount(struct tty_struct *tty,
struct uart_state *state = tty->driver_data;
struct uart_icount cnow;
struct uart_port *uport;
+ unsigned long flags;
- uport = uart_port_ref(state);
+ uport = uart_port_ref_lock(state, &flags);
if (!uport)
return -EIO;
- uart_port_lock_irq(uport);
memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
- uart_port_unlock_irq(uport);
- uart_port_deref(uport);
+ uart_port_unlock_deref(uport, flags);
icount->cts = cnow.cts;
icount->dsr = cnow.dsr;
@@ -1337,28 +1337,28 @@ static void uart_sanitize_serial_rs485_delays(struct uart_port *port,
if (!port->rs485_supported.delay_rts_before_send) {
if (rs485->delay_rts_before_send) {
dev_warn_ratelimited(port->dev,
- "%s (%d): RTS delay before sending not supported\n",
+ "%s (%u): RTS delay before sending not supported\n",
port->name, port->line);
}
rs485->delay_rts_before_send = 0;
} else if (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) {
rs485->delay_rts_before_send = RS485_MAX_RTS_DELAY;
dev_warn_ratelimited(port->dev,
- "%s (%d): RTS delay before sending clamped to %u ms\n",
+ "%s (%u): RTS delay before sending clamped to %u ms\n",
port->name, port->line, rs485->delay_rts_before_send);
}
if (!port->rs485_supported.delay_rts_after_send) {
if (rs485->delay_rts_after_send) {
dev_warn_ratelimited(port->dev,
- "%s (%d): RTS delay after sending not supported\n",
+ "%s (%u): RTS delay after sending not supported\n",
port->name, port->line);
}
rs485->delay_rts_after_send = 0;
} else if (rs485->delay_rts_after_send > RS485_MAX_RTS_DELAY) {
rs485->delay_rts_after_send = RS485_MAX_RTS_DELAY;
dev_warn_ratelimited(port->dev,
- "%s (%d): RTS delay after sending clamped to %u ms\n",
+ "%s (%u): RTS delay after sending clamped to %u ms\n",
port->name, port->line, rs485->delay_rts_after_send);
}
}
@@ -1388,14 +1388,14 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
dev_warn_ratelimited(port->dev,
- "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n",
+ "%s (%u): invalid RTS setting, using RTS_ON_SEND instead\n",
port->name, port->line);
} else {
rs485->flags |= SER_RS485_RTS_AFTER_SEND;
rs485->flags &= ~SER_RS485_RTS_ON_SEND;
dev_warn_ratelimited(port->dev,
- "%s (%d): invalid RTS setting, using RTS_AFTER_SEND instead\n",
+ "%s (%u): invalid RTS setting, using RTS_AFTER_SEND instead\n",
port->name, port->line);
}
}
@@ -1834,7 +1834,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
expire = jiffies + timeout;
- pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
+ pr_debug("uart_wait_until_sent(%u), jiffies=%lu, expire=%lu...\n",
port->line, jiffies, expire);
/*
@@ -1914,9 +1914,10 @@ static bool uart_carrier_raised(struct tty_port *port)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
+ unsigned long flags;
int mctrl;
- uport = uart_port_ref(state);
+ uport = uart_port_ref_lock(state, &flags);
/*
* Should never observe uport == NULL since checks for hangup should
* abort the tty_port_block_til_ready() loop before checking for carrier
@@ -1925,11 +1926,9 @@ static bool uart_carrier_raised(struct tty_port *port)
*/
if (WARN_ON(!uport))
return true;
- uart_port_lock_irq(uport);
uart_enable_ms(uport);
mctrl = uport->ops->get_mctrl(uport);
- uart_port_unlock_irq(uport);
- uart_port_deref(uport);
+ uart_port_unlock_deref(uport, flags);
return mctrl & TIOCM_CAR;
}
@@ -2029,7 +2028,7 @@ static void uart_line_info(struct seq_file *m, struct uart_state *state)
return;
mmio = uport->iotype >= UPIO_MEM;
- seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
+ seq_printf(m, "%u: uart:%s %s%08llX irq:%u",
uport->line, uart_type(uport),
mmio ? "mmio:0x" : "port:",
mmio ? (unsigned long long)uport->mapbase
@@ -2051,18 +2050,18 @@ static void uart_line_info(struct seq_file *m, struct uart_state *state)
if (pm_state != UART_PM_STATE_ON)
uart_change_pm(state, pm_state);
- seq_printf(m, " tx:%d rx:%d",
+ seq_printf(m, " tx:%u rx:%u",
uport->icount.tx, uport->icount.rx);
if (uport->icount.frame)
- seq_printf(m, " fe:%d", uport->icount.frame);
+ seq_printf(m, " fe:%u", uport->icount.frame);
if (uport->icount.parity)
- seq_printf(m, " pe:%d", uport->icount.parity);
+ seq_printf(m, " pe:%u", uport->icount.parity);
if (uport->icount.brk)
- seq_printf(m, " brk:%d", uport->icount.brk);
+ seq_printf(m, " brk:%u", uport->icount.brk);
if (uport->icount.overrun)
- seq_printf(m, " oe:%d", uport->icount.overrun);
+ seq_printf(m, " oe:%u", uport->icount.overrun);
if (uport->icount.buf_overrun)
- seq_printf(m, " bo:%d", uport->icount.buf_overrun);
+ seq_printf(m, " bo:%u", uport->icount.buf_overrun);
#define INFOBIT(bit, str) \
if (uport->mctrl & (bit)) \
@@ -2133,33 +2132,6 @@ void uart_console_write(struct uart_port *port, const char *s,
EXPORT_SYMBOL_GPL(uart_console_write);
/**
- * uart_get_console - get uart port for console
- * @ports: ports to search in
- * @nr: number of @ports
- * @co: console to search for
- * Returns: uart_port for the console @co
- *
- * Check whether an invalid uart number has been specified (as @co->index), and
- * if so, search for the first available port that does have console support.
- */
-struct uart_port * __init
-uart_get_console(struct uart_port *ports, int nr, struct console *co)
-{
- int idx = co->index;
-
- if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 &&
- ports[idx].membase == NULL))
- for (idx = 0; idx < nr; idx++)
- if (ports[idx].iobase != 0 ||
- ports[idx].membase != NULL)
- break;
-
- co->index = idx;
-
- return ports + idx;
-}
-
-/**
* uart_parse_earlycon - Parse earlycon options
* @p: ptr to 2nd field (ie., just beyond '<name>,')
* @iotype: ptr for decoded iotype (out)
@@ -2178,8 +2150,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
*
* Returns: 0 on success or -%EINVAL on failure
*/
-int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
- char **options)
+int uart_parse_earlycon(char *p, enum uart_iotype *iotype,
+ resource_size_t *addr, char **options)
{
if (strncmp(p, "mmio,", 5) == 0) {
*iotype = UPIO_MEM;
@@ -2554,7 +2526,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
break;
}
- pr_info("%s%s%s at %s (irq = %d, base_baud = %d) is a %s\n",
+ pr_info("%s%s%s at %s (irq = %u, base_baud = %u) is a %s\n",
port->dev ? dev_name(port->dev) : "",
port->dev ? ": " : "",
port->name,
@@ -2562,7 +2534,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
/* The magic multiplier feature is a bit obscure, so report it too. */
if (port->flags & UPF_MAGIC_MULTIPLIER)
- pr_info("%s%s%s extra baud rates supported: %d, %d",
+ pr_info("%s%s%s extra baud rates supported: %u, %u",
port->dev ? dev_name(port->dev) : "",
port->dev ? ": " : "",
port->name,
@@ -2961,7 +2933,7 @@ static ssize_t close_delay_show(struct device *dev,
struct tty_port *port = dev_get_drvdata(dev);
uart_get_info(port, &tmp);
- return sprintf(buf, "%d\n", tmp.close_delay);
+ return sprintf(buf, "%u\n", tmp.close_delay);
}
static ssize_t closing_wait_show(struct device *dev,
@@ -2971,7 +2943,7 @@ static ssize_t closing_wait_show(struct device *dev,
struct tty_port *port = dev_get_drvdata(dev);
uart_get_info(port, &tmp);
- return sprintf(buf, "%d\n", tmp.closing_wait);
+ return sprintf(buf, "%u\n", tmp.closing_wait);
}
static ssize_t custom_divisor_show(struct device *dev,
@@ -2991,7 +2963,7 @@ static ssize_t io_type_show(struct device *dev,
struct tty_port *port = dev_get_drvdata(dev);
uart_get_info(port, &tmp);
- return sprintf(buf, "%d\n", tmp.io_type);
+ return sprintf(buf, "%u\n", tmp.io_type);
}
static ssize_t iomem_base_show(struct device *dev,
@@ -3011,7 +2983,7 @@ static ssize_t iomem_reg_shift_show(struct device *dev,
struct tty_port *port = dev_get_drvdata(dev);
uart_get_info(port, &tmp);
- return sprintf(buf, "%d\n", tmp.iomem_reg_shift);
+ return sprintf(buf, "%u\n", tmp.iomem_reg_shift);
}
static ssize_t console_show(struct device *dev,
@@ -3147,7 +3119,7 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
state->pm_state = UART_PM_STATE_UNDEFINED;
uart_port_set_cons(uport, drv->cons);
uport->minor = drv->tty_driver->minor_start + uport->line;
- uport->name = kasprintf(GFP_KERNEL, "%s%d", drv->dev_name,
+ uport->name = kasprintf(GFP_KERNEL, "%s%u", drv->dev_name,
drv->tty_driver->name_base + uport->line);
if (!uport->name)
return -ENOMEM;
@@ -3186,7 +3158,7 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
device_set_wakeup_capable(tty_dev, 1);
} else {
uport->flags |= UPF_DEAD;
- dev_err(uport->dev, "Cannot register tty device on line %d\n",
+ dev_err(uport->dev, "Cannot register tty device on line %u\n",
uport->line);
}
@@ -3210,7 +3182,6 @@ static void serial_core_remove_one_port(struct uart_driver *drv,
struct uart_state *state = drv->state + uport->line;
struct tty_port *port = &state->port;
struct uart_port *uart_port;
- struct tty_struct *tty;
mutex_lock(&port->mutex);
uart_port = uart_port_check(state);
@@ -3229,11 +3200,7 @@ static void serial_core_remove_one_port(struct uart_driver *drv,
*/
tty_port_unregister_device(port, drv->tty_driver, uport->line);
- tty = tty_port_tty_get(port);
- if (tty) {
- tty_vhangup(port->tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_vhangup(port);
/*
* If the port is used as a console, unregister it
@@ -3289,9 +3256,9 @@ bool uart_match_port(const struct uart_port *port1,
case UPIO_AU:
case UPIO_TSI:
return port1->mapbase == port2->mapbase;
+ default:
+ return false;
}
-
- return false;
}
EXPORT_SYMBOL(uart_match_port);
diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci-common.h
new file mode 100644
index 000000000000..e3c028df14f1
--- /dev/null
+++ b/drivers/tty/serial/sh-sci-common.h
@@ -0,0 +1,175 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __SH_SCI_COMMON_H__
+#define __SH_SCI_COMMON_H__
+
+#include <linux/serial_core.h>
+
+/* Private port IDs */
+enum SCI_PORT_TYPE {
+ SCI_PORT_RSCI = BIT(7) | 0,
+};
+
+enum SCI_CLKS {
+ SCI_FCK, /* Functional Clock */
+ SCI_SCK, /* Optional External Clock */
+ SCI_BRG_INT, /* Optional BRG Internal Clock Source */
+ SCI_SCIF_CLK, /* Optional BRG External Clock Source */
+ SCI_NUM_CLKS
+};
+
+/* Offsets into the sci_port->irqs array */
+enum {
+ SCIx_ERI_IRQ,
+ SCIx_RXI_IRQ,
+ SCIx_TXI_IRQ,
+ SCIx_BRI_IRQ,
+ SCIx_DRI_IRQ,
+ SCIx_TEI_IRQ,
+ SCIx_NR_IRQS,
+
+ SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */
+};
+
+/* 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)
+
+void sci_release_port(struct uart_port *port);
+int sci_request_port(struct uart_port *port);
+void sci_config_port(struct uart_port *port, int flags);
+int sci_verify_port(struct uart_port *port, struct serial_struct *ser);
+void sci_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate);
+
+struct plat_sci_reg {
+ u8 offset;
+ u8 size;
+};
+
+struct sci_port_params_bits {
+ unsigned int rxtx_enable;
+ unsigned int te_clear;
+ unsigned int poll_sent_bits;
+};
+
+struct sci_common_regs {
+ unsigned int status;
+ unsigned int control;
+};
+
+/* The actual number of needed registers. This is used by sci only */
+#define SCI_NR_REGS 20
+
+struct sci_port_params {
+ const struct plat_sci_reg regs[SCI_NR_REGS];
+ const struct sci_common_regs *common_regs;
+ const struct sci_port_params_bits *param_bits;
+ unsigned int fifosize;
+ unsigned int overrun_reg;
+ unsigned int overrun_mask;
+ unsigned int sampling_rate_mask;
+ unsigned int error_mask;
+ unsigned int error_clear;
+};
+
+struct sci_port_ops {
+ u32 (*read_reg)(struct uart_port *port, int reg);
+ void (*write_reg)(struct uart_port *port, int reg, int value);
+ void (*clear_SCxSR)(struct uart_port *port, unsigned int mask);
+
+ void (*transmit_chars)(struct uart_port *port);
+ void (*receive_chars)(struct uart_port *port);
+
+ void (*poll_put_char)(struct uart_port *port, unsigned char c);
+
+ int (*set_rtrg)(struct uart_port *port, int rx_trig);
+ int (*rtrg_enabled)(struct uart_port *port);
+
+ void (*shutdown_complete)(struct uart_port *port);
+
+ void (*prepare_console_write)(struct uart_port *port, u32 ctrl);
+ void (*console_save)(struct uart_port *port);
+ void (*console_restore)(struct uart_port *port);
+ size_t (*suspend_regs_size)(void);
+};
+
+struct sci_of_data {
+ const struct sci_port_params *params;
+ const struct uart_ops *uart_ops;
+ const struct sci_port_ops *ops;
+ unsigned short regtype;
+ unsigned short type;
+};
+
+struct sci_port {
+ struct uart_port port;
+
+ /* Platform configuration */
+ const struct sci_port_params *params;
+ const struct plat_sci_port *cfg;
+
+ unsigned int sampling_rate_mask;
+ resource_size_t reg_size;
+ struct mctrl_gpios *gpios;
+
+ /* Clocks */
+ struct clk *clks[SCI_NUM_CLKS];
+ unsigned long clk_rates[SCI_NUM_CLKS];
+
+ int irqs[SCIx_NR_IRQS];
+ char *irqstr[SCIx_NR_IRQS];
+
+ struct dma_chan *chan_tx;
+ struct dma_chan *chan_rx;
+
+ struct reset_control *rstc;
+ struct sci_suspend_regs *suspend_regs;
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+ struct dma_chan *chan_tx_saved;
+ struct dma_chan *chan_rx_saved;
+ dma_cookie_t cookie_tx;
+ dma_cookie_t cookie_rx[2];
+ dma_cookie_t active_rx;
+ 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 work_struct work_tx;
+ struct hrtimer rx_timer;
+ unsigned int rx_timeout; /* microseconds */
+#endif
+ unsigned int rx_frame;
+ int rx_trigger;
+ struct timer_list rx_fifo_timer;
+ int rx_fifo_timeout;
+ u16 hscif_tot;
+
+ u8 type;
+ u8 regtype;
+
+ const struct sci_port_ops *ops;
+
+ bool has_rtscts;
+ bool autorts;
+ bool tx_occurred;
+};
+
+#define to_sci_port(uart) container_of((uart), struct sci_port, port)
+
+void sci_port_disable(struct sci_port *sci_port);
+void sci_port_enable(struct sci_port *sci_port);
+
+int sci_startup(struct uart_port *port);
+void sci_shutdown(struct uart_port *port);
+
+#define min_sr(_port) ffs((_port)->sampling_rate_mask)
+#define max_sr(_port) fls((_port)->sampling_rate_mask)
+
+#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
+int __init scix_early_console_setup(struct earlycon_device *device, const struct sci_of_data *data);
+#endif
+
+#endif /* __SH_SCI_COMMON_H__ */
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 7e7813ccda41..538b2f991609 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -54,21 +54,10 @@
#include <asm/platform_early.h>
#endif
+#include "rsci.h"
#include "serial_mctrl_gpio.h"
#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_DRI_IRQ,
- SCIx_TEI_IRQ,
- SCIx_NR_IRQS,
-
- SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */
-};
+#include "sh-sci-common.h"
#define SCIx_IRQ_IS_MUXED(port) \
((port)->irqs[SCIx_ERI_IRQ] == \
@@ -76,32 +65,40 @@ enum {
((port)->irqs[SCIx_ERI_IRQ] && \
((port)->irqs[SCIx_RXI_IRQ] < 0))
-enum SCI_CLKS {
- SCI_FCK, /* Functional Clock */
- SCI_SCK, /* Optional External Clock */
- SCI_BRG_INT, /* Optional BRG Internal Clock Source */
- SCI_SCIF_CLK, /* Optional BRG External Clock Source */
- 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 plat_sci_reg {
- u8 offset, size;
+#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
+
+#define SCI_PUBLIC_PORT_ID(port) (((port) & BIT(7)) ? PORT_GENERIC : (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 const struct sci_port_params_bits sci_sci_port_params_bits = {
+ .rxtx_enable = SCSCR_RE | SCSCR_TE,
+ .te_clear = SCSCR_TE | SCSCR_TEIE,
+ .poll_sent_bits = SCI_TDRE | SCI_TEND
+};
+
+static const struct sci_port_params_bits sci_scif_port_params_bits = {
+ .rxtx_enable = SCSCR_RE | SCSCR_TE,
+ .te_clear = SCSCR_TE | SCSCR_TEIE,
+ .poll_sent_bits = SCIF_TDFE | SCIF_TEND
+};
+
+static const struct sci_common_regs sci_common_regs = {
+ .status = SCxSR,
+ .control = SCSCR,
};
struct sci_suspend_regs {
@@ -118,77 +115,9 @@ struct sci_suspend_regs {
u8 semr;
};
-struct sci_port_params {
- const struct plat_sci_reg regs[SCIx_NR_REGS];
- unsigned int fifosize;
- unsigned int overrun_reg;
- unsigned int overrun_mask;
- unsigned int sampling_rate_mask;
- unsigned int error_mask;
- unsigned int error_clear;
-};
-
-struct sci_port {
- struct uart_port port;
-
- /* Platform configuration */
- const struct sci_port_params *params;
- const struct plat_sci_port *cfg;
- unsigned int sampling_rate_mask;
- resource_size_t reg_size;
- struct mctrl_gpios *gpios;
-
- /* Clocks */
- struct clk *clks[SCI_NUM_CLKS];
- unsigned long clk_rates[SCI_NUM_CLKS];
-
- int irqs[SCIx_NR_IRQS];
- char *irqstr[SCIx_NR_IRQS];
-
- struct dma_chan *chan_tx;
- struct dma_chan *chan_rx;
-
- struct reset_control *rstc;
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
- struct dma_chan *chan_tx_saved;
- struct dma_chan *chan_rx_saved;
- dma_cookie_t cookie_tx;
- dma_cookie_t cookie_rx[2];
- dma_cookie_t active_rx;
- 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 work_struct work_tx;
- struct hrtimer rx_timer;
- unsigned int rx_timeout; /* microseconds */
-#endif
- unsigned int rx_frame;
- int rx_trigger;
- struct timer_list rx_fifo_timer;
- int rx_fifo_timeout;
- struct sci_suspend_regs suspend_regs;
- u16 hscif_tot;
-
- bool has_rtscts;
- bool autorts;
- bool tx_occurred;
-};
-
-#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
-
-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)
+static size_t sci_suspend_regs_size(void)
{
- return container_of(uart, struct sci_port, port);
+ return sizeof(struct sci_suspend_regs);
}
static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
@@ -211,6 +140,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER,
.error_clear = SCI_ERROR_CLEAR & ~SCI_ORER,
+ .param_bits = &sci_sci_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -233,6 +164,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER,
.error_clear = SCI_ERROR_CLEAR & ~SCI_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -257,6 +190,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR_SCIFAB,
.error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
.error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -282,6 +217,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR_SCIFAB,
.error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
.error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -307,10 +244,12 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
- * The "SCIFA" that is in RZ/A2, RZ/G2L and RZ/T.
+ * The "SCIFA" that is in RZ/A2, RZ/G2L and RZ/T1.
* It looks like a normal SCIF with FIFO data, but with a
* compressed address space. Also, the break out of interrupts
* are different: ERI/BRI, RXI, TXI, TEI, DRI.
@@ -335,6 +274,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -366,6 +307,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -388,6 +331,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -412,6 +357,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -439,6 +386,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -468,6 +417,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR_RANGE(8, 32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -492,6 +443,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -519,6 +472,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -542,6 +497,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(16),
.error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
.error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
};
@@ -579,7 +536,7 @@ static void sci_serial_out(struct uart_port *p, int offset, int value)
WARN(1, "Invalid register access\n");
}
-static void sci_port_enable(struct sci_port *sci_port)
+void sci_port_enable(struct sci_port *sci_port)
{
unsigned int i;
@@ -594,8 +551,9 @@ static void sci_port_enable(struct sci_port *sci_port)
}
sci_port->port.uartclk = sci_port->clk_rates[SCI_FCK];
}
+EXPORT_SYMBOL_NS_GPL(sci_port_enable, "SH_SCI");
-static void sci_port_disable(struct sci_port *sci_port)
+void sci_port_disable(struct sci_port *sci_port)
{
unsigned int i;
@@ -607,6 +565,7 @@ static void sci_port_disable(struct sci_port *sci_port)
pm_runtime_put_sync(sci_port->port.dev);
}
+EXPORT_SYMBOL_NS_GPL(sci_port_disable, "SH_SCI");
static inline unsigned long port_rx_irq_mask(struct uart_port *port)
{
@@ -626,7 +585,7 @@ static void sci_start_tx(struct uart_port *port)
unsigned short ctrl;
#ifdef CONFIG_SERIAL_SH_SCI_DMA
- if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+ if (s->type == PORT_SCIFA || s->type == PORT_SCIFB) {
u16 new, scr = sci_serial_in(port, SCSCR);
if (s->chan_tx)
new = scr | SCSCR_TDRQE;
@@ -638,7 +597,7 @@ static void sci_start_tx(struct uart_port *port)
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)
+ if (s->regtype == SCIx_RZ_SCIFA_REGTYPE)
/* Switch irq from SCIF to DMA */
disable_irq_nosync(s->irqs[SCIx_TXI_IRQ]);
@@ -647,8 +606,8 @@ static void sci_start_tx(struct uart_port *port)
}
#endif
- if (!s->chan_tx || s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE ||
- port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+ if (!s->chan_tx || s->regtype == SCIx_RZ_SCIFA_REGTYPE ||
+ s->type == PORT_SCIFA || s->type == PORT_SCIFB) {
/* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
ctrl = sci_serial_in(port, SCSCR);
@@ -657,7 +616,7 @@ static void sci_start_tx(struct uart_port *port)
* (transmit interrupt enable) or in the same instruction to start
* the transmit process.
*/
- if (port->type == PORT_SCI)
+ if (s->type == PORT_SCI)
ctrl |= SCSCR_TE;
sci_serial_out(port, SCSCR, ctrl | SCSCR_TIE);
@@ -666,12 +625,13 @@ static void sci_start_tx(struct uart_port *port)
static void sci_stop_tx(struct uart_port *port)
{
+ struct sci_port *s = to_sci_port(port);
unsigned short ctrl;
/* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
ctrl = sci_serial_in(port, SCSCR);
- if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+ if (s->type == PORT_SCIFA || s->type == PORT_SCIFB)
ctrl &= ~SCSCR_TDRQE;
ctrl &= ~SCSCR_TIE;
@@ -679,21 +639,22 @@ static void sci_stop_tx(struct uart_port *port)
sci_serial_out(port, SCSCR, ctrl);
#ifdef CONFIG_SERIAL_SH_SCI_DMA
- if (to_sci_port(port)->chan_tx &&
- !dma_submit_error(to_sci_port(port)->cookie_tx)) {
- dmaengine_terminate_async(to_sci_port(port)->chan_tx);
- to_sci_port(port)->cookie_tx = -EINVAL;
+ if (s->chan_tx &&
+ !dma_submit_error(s->cookie_tx)) {
+ dmaengine_terminate_async(s->chan_tx);
+ s->cookie_tx = -EINVAL;
}
#endif
}
static void sci_start_rx(struct uart_port *port)
{
+ struct sci_port *s = to_sci_port(port);
unsigned short ctrl;
ctrl = sci_serial_in(port, SCSCR) | port_rx_irq_mask(port);
- if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+ if (s->type == PORT_SCIFA || s->type == PORT_SCIFB)
ctrl &= ~SCSCR_RDRQE;
sci_serial_out(port, SCSCR, ctrl);
@@ -701,11 +662,12 @@ static void sci_start_rx(struct uart_port *port)
static void sci_stop_rx(struct uart_port *port)
{
+ struct sci_port *s = to_sci_port(port);
unsigned short ctrl;
ctrl = sci_serial_in(port, SCSCR);
- if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+ if (s->type == PORT_SCIFA || s->type == PORT_SCIFB)
ctrl &= ~SCSCR_RDRQE;
ctrl &= ~port_rx_irq_mask(port);
@@ -715,10 +677,12 @@ static void sci_stop_rx(struct uart_port *port)
static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
{
- if (port->type == PORT_SCI) {
+ struct sci_port *s = to_sci_port(port);
+
+ if (s->type == PORT_SCI) {
/* Just store the mask */
sci_serial_out(port, SCxSR, mask);
- } else if (to_sci_port(port)->params->overrun_mask == SCIFA_ORER) {
+ } else if (s->params->overrun_mask == SCIFA_ORER) {
/* SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 */
/* Only clear the status bits we want to clear */
sci_serial_out(port, SCxSR, sci_serial_in(port, SCxSR) & mask);
@@ -735,12 +699,13 @@ static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
static int sci_poll_get_char(struct uart_port *port)
{
unsigned short status;
+ struct sci_port *s = to_sci_port(port);
int c;
do {
status = sci_serial_in(port, SCxSR);
if (status & SCxSR_ERRORS(port)) {
- sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
continue;
}
break;
@@ -753,7 +718,7 @@ static int sci_poll_get_char(struct uart_port *port)
/* Dummy read */
sci_serial_in(port, SCxSR);
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
return c;
}
@@ -761,14 +726,16 @@ static int sci_poll_get_char(struct uart_port *port)
static void sci_poll_put_char(struct uart_port *port, unsigned char c)
{
- unsigned short status;
+ struct sci_port *s = to_sci_port(port);
+ const struct sci_common_regs *regs = s->params->common_regs;
+ unsigned int status;
do {
- status = sci_serial_in(port, SCxSR);
+ status = s->ops->read_reg(port, regs->status);
} while (!(status & SCxSR_TDxE(port)));
sci_serial_out(port, SCxTDR, c);
- sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
+ s->ops->clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
}
#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE ||
CONFIG_SERIAL_SH_SCI_EARLYCON */
@@ -785,13 +752,13 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
return;
}
- if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+ if (s->type == PORT_SCIFA || s->type == PORT_SCIFB) {
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);
- if (to_sci_port(port)->has_rtscts) {
+ if (s->has_rtscts) {
/* RTS# is output, active low, unless autorts */
if (!(port->mctrl & TIOCM_RTS)) {
ctrl |= SCPCR_RTSC;
@@ -808,7 +775,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
}
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) {
+ } else if (sci_getreg(port, SCSPTR)->size && s->regtype != SCIx_RZV2H_SCIF_REGTYPE) {
u16 status = sci_serial_in(port, SCSPTR);
/* RTS# is always output; and active low, unless autorts */
@@ -895,8 +862,8 @@ static void sci_transmit_chars(struct uart_port *port)
c = port->x_char;
port->x_char = 0;
} else if (stopped || !kfifo_get(&tport->xmit_fifo, &c)) {
- if (port->type == PORT_SCI &&
- kfifo_is_empty(&tport->xmit_fifo)) {
+ if (s->type == PORT_SCI &&
+ kfifo_is_empty(&tport->xmit_fifo)) {
ctrl = sci_serial_in(port, SCSCR);
ctrl &= ~SCSCR_TE;
sci_serial_out(port, SCSCR, ctrl);
@@ -911,12 +878,12 @@ static void sci_transmit_chars(struct uart_port *port)
port->icount.tx++;
} while (--count > 0);
- sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (kfifo_is_empty(&tport->xmit_fifo)) {
- if (port->type == PORT_SCI) {
+ if (s->type == PORT_SCI) {
ctrl = sci_serial_in(port, SCSCR);
ctrl &= ~SCSCR_TIE;
ctrl |= SCSCR_TEIE;
@@ -930,6 +897,7 @@ static void sci_transmit_chars(struct uart_port *port)
static void sci_receive_chars(struct uart_port *port)
{
struct tty_port *tport = &port->state->port;
+ struct sci_port *s = to_sci_port(port);
int i, count, copied = 0;
unsigned short status;
unsigned char flag;
@@ -946,7 +914,7 @@ static void sci_receive_chars(struct uart_port *port)
if (count == 0)
break;
- if (port->type == PORT_SCI) {
+ if (s->type == PORT_SCI) {
char c = sci_serial_in(port, SCxRDR);
if (uart_handle_sysrq_char(port, c))
count = 0;
@@ -956,8 +924,8 @@ static void sci_receive_chars(struct uart_port *port)
for (i = 0; i < count; i++) {
char c;
- if (port->type == PORT_SCIF ||
- port->type == PORT_HSCIF) {
+ if (s->type == PORT_SCIF ||
+ s->type == PORT_HSCIF) {
status = sci_serial_in(port, SCxSR);
c = sci_serial_in(port, SCxRDR);
} else {
@@ -984,7 +952,7 @@ static void sci_receive_chars(struct uart_port *port)
}
sci_serial_in(port, SCxSR); /* dummy read */
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
copied += count;
port->icount.rx += count;
@@ -997,16 +965,17 @@ static void sci_receive_chars(struct uart_port *port)
/* TTY buffers full; read from RX reg to prevent lockup */
sci_serial_in(port, SCxRDR);
sci_serial_in(port, SCxSR); /* dummy read */
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
}
}
static int sci_handle_errors(struct uart_port *port)
{
int copied = 0;
- unsigned short status = sci_serial_in(port, SCxSR);
- struct tty_port *tport = &port->state->port;
struct sci_port *s = to_sci_port(port);
+ const struct sci_common_regs *regs = s->params->common_regs;
+ unsigned int status = s->ops->read_reg(port, regs->status);
+ struct tty_port *tport = &port->state->port;
/* Handle overruns */
if (status & s->params->overrun_mask) {
@@ -1093,6 +1062,7 @@ static int sci_handle_breaks(struct uart_port *port)
static int scif_set_rtrg(struct uart_port *port, int rx_trig)
{
+ struct sci_port *s = to_sci_port(port);
unsigned int bits;
if (rx_trig >= port->fifosize)
@@ -1106,7 +1076,7 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig)
return rx_trig;
}
- switch (port->type) {
+ switch (s->type) {
case PORT_SCIF:
if (rx_trig < 4) {
bits = 0;
@@ -1161,11 +1131,11 @@ static int scif_rtrg_enabled(struct uart_port *port)
static void rx_fifo_timer_fn(struct timer_list *t)
{
- struct sci_port *s = from_timer(s, t, rx_fifo_timer);
+ struct sci_port *s = timer_container_of(s, t, rx_fifo_timer);
struct uart_port *port = &s->port;
dev_dbg(port->dev, "Rx timed out\n");
- scif_set_rtrg(port, 1);
+ s->ops->set_rtrg(port, 1);
}
static ssize_t rx_fifo_trigger_show(struct device *dev,
@@ -1190,9 +1160,9 @@ static ssize_t rx_fifo_trigger_store(struct device *dev,
if (ret)
return ret;
- sci->rx_trigger = scif_set_rtrg(port, r);
- if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
- scif_set_rtrg(port, 1);
+ sci->rx_trigger = sci->ops->set_rtrg(port, r);
+ if (sci->type == PORT_SCIFA || sci->type == PORT_SCIFB)
+ sci->ops->set_rtrg(port, 1);
return count;
}
@@ -1207,7 +1177,7 @@ static ssize_t rx_fifo_timeout_show(struct device *dev,
struct sci_port *sci = to_sci_port(port);
int v;
- if (port->type == PORT_HSCIF)
+ if (sci->type == PORT_HSCIF)
v = sci->hscif_tot >> HSSCR_TOT_SHIFT;
else
v = sci->rx_fifo_timeout;
@@ -1229,13 +1199,13 @@ static ssize_t rx_fifo_timeout_store(struct device *dev,
if (ret)
return ret;
- if (port->type == PORT_HSCIF) {
+ if (sci->type == PORT_HSCIF) {
if (r < 0 || r > 3)
return -EINVAL;
sci->hscif_tot = r << HSSCR_TOT_SHIFT;
} else {
sci->rx_fifo_timeout = r;
- scif_set_rtrg(port, 1);
+ sci->ops->set_rtrg(port, 1);
if (r > 0)
timer_setup(&sci->rx_fifo_timer, rx_fifo_timer_fn, 0);
}
@@ -1270,11 +1240,11 @@ static void sci_dma_tx_complete(void *arg)
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) {
+ if (s->type == PORT_SCIFA || s->type == PORT_SCIFB ||
+ s->regtype == SCIx_RZ_SCIFA_REGTYPE) {
u16 ctrl = sci_serial_in(port, SCSCR);
sci_serial_out(port, SCSCR, ctrl & ~SCSCR_TIE);
- if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
+ if (s->regtype == SCIx_RZ_SCIFA_REGTYPE) {
/* Switch irq from DMA to SCIF */
dmaengine_pause(s->chan_tx_saved);
enable_irq(s->irqs[SCIx_TXI_IRQ]);
@@ -1356,11 +1326,11 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s)
/* Direct new serial port interrupts back to CPU */
scr = sci_serial_in(port, SCSCR);
- if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
- s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
+ if (s->type == PORT_SCIFA || s->type == PORT_SCIFB ||
+ s->regtype == SCIx_RZ_SCIFA_REGTYPE) {
enable_irq(s->irqs[SCIx_RXI_IRQ]);
- if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE)
- scif_set_rtrg(port, s->rx_trigger);
+ if (s->regtype == SCIx_RZ_SCIFA_REGTYPE)
+ s->ops->set_rtrg(port, s->rx_trigger);
else
scr &= ~SCSCR_RDRQE;
}
@@ -1599,8 +1569,8 @@ static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t)
tty_flip_buffer_push(&port->state->port);
}
- if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
- s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE)
+ if (s->type == PORT_SCIFA || s->type == PORT_SCIFB ||
+ s->regtype == SCIx_RZ_SCIFA_REGTYPE)
sci_dma_rx_submit(s, true);
sci_dma_rx_reenable_irq(s);
@@ -1723,8 +1693,8 @@ static void sci_request_dma(struct uart_port *port)
s->chan_rx_saved = s->chan_rx = chan;
- if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
- s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE)
+ if (s->type == PORT_SCIFA || s->type == PORT_SCIFB ||
+ s->regtype == SCIx_RZ_SCIFA_REGTYPE)
sci_dma_rx_submit(s, false);
}
}
@@ -1794,11 +1764,11 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
u16 ssr = sci_serial_in(port, SCxSR);
/* Disable future Rx interrupts */
- if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
- s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
+ if (s->type == PORT_SCIFA || s->type == PORT_SCIFB ||
+ s->regtype == SCIx_RZ_SCIFA_REGTYPE) {
disable_irq_nosync(s->irqs[SCIx_RXI_IRQ]);
- if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
- scif_set_rtrg(port, 1);
+ if (s->regtype == SCIx_RZ_SCIFA_REGTYPE) {
+ s->ops->set_rtrg(port, 1);
scr |= SCSCR_RIE;
} else {
scr |= SCSCR_RDRQE;
@@ -1824,8 +1794,8 @@ handle_pio:
#endif
if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0) {
- if (!scif_rtrg_enabled(port))
- scif_set_rtrg(port, s->rx_trigger);
+ if (!s->ops->rtrg_enabled(port))
+ s->ops->set_rtrg(port, s->rx_trigger);
mod_timer(&s->rx_fifo_timer, jiffies + DIV_ROUND_UP(
s->rx_frame * HZ * s->rx_fifo_timeout, 1000000));
@@ -1835,7 +1805,7 @@ handle_pio:
* of whether the I_IXOFF is set, otherwise, how is the interrupt
* to be disabled?
*/
- sci_receive_chars(port);
+ s->ops->receive_chars(port);
return IRQ_HANDLED;
}
@@ -1844,9 +1814,10 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
unsigned long flags;
+ struct sci_port *s = to_sci_port(port);
uart_port_lock_irqsave(port, &flags);
- sci_transmit_chars(port);
+ s->ops->transmit_chars(port);
uart_port_unlock_irqrestore(port, flags);
return IRQ_HANDLED;
@@ -1855,16 +1826,18 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
+ struct sci_port *s = to_sci_port(port);
+ const struct sci_common_regs *regs = s->params->common_regs;
unsigned long flags;
- unsigned short ctrl;
+ u32 ctrl;
- if (port->type != PORT_SCI)
+ if (s->type != PORT_SCI && s->type != SCI_PORT_RSCI)
return sci_tx_interrupt(irq, ptr);
uart_port_lock_irqsave(port, &flags);
- ctrl = sci_serial_in(port, SCSCR);
- ctrl &= ~(SCSCR_TE | SCSCR_TEIE);
- sci_serial_out(port, SCSCR, ctrl);
+ ctrl = s->ops->read_reg(port, regs->control) &
+ ~(s->params->param_bits->te_clear);
+ s->ops->write_reg(port, regs->control, ctrl);
uart_port_unlock_irqrestore(port, flags);
return IRQ_HANDLED;
@@ -1873,6 +1846,7 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
static irqreturn_t sci_br_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
+ struct sci_port *s = to_sci_port(port);
/* Handle BREAKs */
sci_handle_breaks(port);
@@ -1880,7 +1854,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
/* drop invalid character received before break was detected */
sci_serial_in(port, SCxRDR);
- sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
return IRQ_HANDLED;
}
@@ -1904,19 +1878,19 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr)
}
/* Handle errors */
- if (port->type == PORT_SCI) {
+ if (s->type == PORT_SCI) {
if (sci_handle_errors(port)) {
/* discard character in rx buffer */
sci_serial_in(port, SCxSR);
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
}
} else {
sci_handle_fifo_overrun(port);
if (!s->chan_rx)
- sci_receive_chars(port);
+ s->ops->receive_chars(port);
}
- sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
/* Kick the transmission */
if (!s->chan_tx)
@@ -2128,7 +2102,9 @@ 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) {
+ struct sci_port *s = to_sci_port(port);
+
+ if (s->type == PORT_SCIFA || s->type == PORT_SCIFB) {
u16 data = sci_serial_in(port, SCPDR);
/* Active low */
@@ -2155,7 +2131,9 @@ static void sci_set_rts(struct uart_port *port, bool state)
static bool sci_get_cts(struct uart_port *port)
{
- if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+ struct sci_port *s = to_sci_port(port);
+
+ if (s->type == PORT_SCIFA || s->type == PORT_SCIFB) {
/* Active low */
return !(sci_serial_in(port, SCPDR) & SCPDR_CTSD);
} else if (sci_getreg(port, SCSPTR)->size) {
@@ -2201,21 +2179,21 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (!(mctrl & TIOCM_RTS)) {
/* Disable Auto RTS */
- if (s->cfg->regtype != SCIx_RZV2H_SCIF_REGTYPE)
+ if (s->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) {
+ if (s->type == PORT_SCIFA || s->type == PORT_SCIFB) {
/* Enable RTS# pin function */
sci_serial_out(port, SCPCR,
sci_serial_in(port, SCPCR) & ~SCPCR_RTSC);
}
/* Enable Auto RTS */
- if (s->cfg->regtype != SCIx_RZV2H_SCIF_REGTYPE)
+ if (s->regtype != SCIx_RZV2H_SCIF_REGTYPE)
sci_serial_out(port, SCFCR,
sci_serial_in(port, SCFCR) | SCFCR_MCE);
} else {
@@ -2286,7 +2264,17 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
uart_port_unlock_irqrestore(port, flags);
}
-static int sci_startup(struct uart_port *port)
+static void sci_shutdown_complete(struct uart_port *port)
+{
+ struct sci_port *s = to_sci_port(port);
+ u16 scr;
+
+ scr = sci_serial_in(port, SCSCR);
+ sci_serial_out(port, SCSCR,
+ scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
+}
+
+int sci_startup(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
int ret;
@@ -2304,12 +2292,12 @@ static int sci_startup(struct uart_port *port)
return 0;
}
+EXPORT_SYMBOL_NS_GPL(sci_startup, "SH_SCI");
-static void sci_shutdown(struct uart_port *port)
+void sci_shutdown(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
unsigned long flags;
- u16 scr;
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
@@ -2317,15 +2305,9 @@ static void sci_shutdown(struct uart_port *port)
mctrl_gpio_disable_ms_sync(to_sci_port(port)->gpios);
uart_port_lock_irqsave(port, &flags);
- sci_stop_rx(port);
- sci_stop_tx(port);
- /*
- * Stop RX and TX, disable related interrupts, keep clock source
- * and HSCIF TOT bits
- */
- scr = sci_serial_in(port, SCSCR);
- sci_serial_out(port, SCSCR,
- scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
+ s->port.ops->stop_rx(port);
+ s->port.ops->stop_tx(port);
+ s->ops->shutdown_complete(port);
uart_port_unlock_irqrestore(port, flags);
#ifdef CONFIG_SERIAL_SH_SCI_DMA
@@ -2341,6 +2323,7 @@ static void sci_shutdown(struct uart_port *port)
sci_free_irq(s);
sci_free_dma(port);
}
+EXPORT_SYMBOL_NS_GPL(sci_shutdown, "SH_SCI");
static int sci_sck_calc(struct sci_port *s, unsigned int bps,
unsigned int *srr)
@@ -2349,7 +2332,7 @@ static int sci_sck_calc(struct sci_port *s, unsigned int bps,
int err, min_err = INT_MAX;
unsigned int sr;
- if (s->port.type != PORT_HSCIF)
+ if (s->type != PORT_HSCIF)
freq *= 2;
for_each_sr(sr, s) {
@@ -2376,7 +2359,7 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps,
int err, min_err = INT_MAX;
unsigned int sr, dl;
- if (s->port.type != PORT_HSCIF)
+ if (s->type != PORT_HSCIF)
freq *= 2;
for_each_sr(sr, s) {
@@ -2402,14 +2385,14 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps,
/* calculate sample rate, BRR, and clock select */
static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
- unsigned int *brr, unsigned int *srr,
- unsigned int *cks)
+ unsigned int *brr, unsigned int *srr,
+ unsigned int *cks)
{
unsigned long freq = s->clk_rates[SCI_FCK];
unsigned int sr, br, prediv, scrate, c;
int err, min_err = INT_MAX;
- if (s->port.type != PORT_HSCIF)
+ if (s->type != PORT_HSCIF)
freq *= 2;
/*
@@ -2480,9 +2463,9 @@ static void sci_reset(struct uart_port *port)
if (reg->size)
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));
+ s->ops->clear_SCxSR(port,
+ SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
+ SCxSR_BREAK_CLEAR(port));
if (sci_getreg(port, SCLSR)->size) {
status = sci_serial_in(port, SCLSR);
status &= ~(SCLSR_TO | SCLSR_ORER);
@@ -2491,14 +2474,14 @@ static void sci_reset(struct uart_port *port)
if (s->rx_trigger > 1) {
if (s->rx_fifo_timeout) {
- scif_set_rtrg(port, 1);
+ s->ops->set_rtrg(port, 1);
timer_setup(&s->rx_fifo_timer, rx_fifo_timer_fn, 0);
} else {
- if (port->type == PORT_SCIFA ||
- port->type == PORT_SCIFB)
- scif_set_rtrg(port, 1);
+ if (s->type == PORT_SCIFA ||
+ s->type == PORT_SCIFB)
+ s->ops->set_rtrg(port, 1);
else
- scif_set_rtrg(port, s->rx_trigger);
+ s->ops->set_rtrg(port, s->rx_trigger);
}
}
}
@@ -2555,8 +2538,8 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
*/
/* Optional Undivided External Clock */
- if (s->clk_rates[SCI_SCK] && port->type != PORT_SCIFA &&
- port->type != PORT_SCIFB) {
+ if (s->clk_rates[SCI_SCK] && s->type != PORT_SCIFA &&
+ s->type != PORT_SCIFB) {
err = sci_sck_calc(s, baud, &srr1);
if (abs(err) < abs(min_err)) {
best_clk = SCI_SCK;
@@ -2641,7 +2624,7 @@ done:
sci_serial_out(port, SEMR, 0);
if (best_clk >= 0) {
- if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+ if (s->type == PORT_SCIFA || s->type == PORT_SCIFB)
switch (srr + 1) {
case 5: smr_val |= SCSMR_SRC_5; break;
case 7: smr_val |= SCSMR_SRC_7; break;
@@ -2726,12 +2709,12 @@ done:
* (transmit interrupt enable) or in the same instruction to
* start the transmitting process. So skip setting TE here for SCI.
*/
- if (port->type != PORT_SCI)
+ if (s->type != PORT_SCI)
scr_val |= SCSCR_TE;
scr_val |= SCSCR_RE | (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0));
sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
if ((srr + 1 == 5) &&
- (port->type == PORT_SCIFA || port->type == PORT_SCIFB)) {
+ (s->type == PORT_SCIFA || s->type == PORT_SCIFB)) {
/*
* In asynchronous mode, when the sampling rate is 1/5, first
* received data may become invalid on some SCIFA and SCIFB.
@@ -2758,7 +2741,7 @@ done:
sci_enable_ms(port);
}
-static void sci_pm(struct uart_port *port, unsigned int state,
+void sci_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct sci_port *sci_port = to_sci_port(port);
@@ -2772,10 +2755,13 @@ static void sci_pm(struct uart_port *port, unsigned int state,
break;
}
}
+EXPORT_SYMBOL_NS_GPL(sci_pm, "SH_SCI");
static const char *sci_type(struct uart_port *port)
{
- switch (port->type) {
+ struct sci_port *s = to_sci_port(port);
+
+ switch (s->type) {
case PORT_IRDA:
return "irda";
case PORT_SCI:
@@ -2821,7 +2807,7 @@ static int sci_remap_port(struct uart_port *port)
return 0;
}
-static void sci_release_port(struct uart_port *port)
+void sci_release_port(struct uart_port *port)
{
struct sci_port *sport = to_sci_port(port);
@@ -2832,8 +2818,9 @@ static void sci_release_port(struct uart_port *port)
release_mem_region(port->mapbase, sport->reg_size);
}
+EXPORT_SYMBOL_NS_GPL(sci_release_port, "SH_SCI");
-static int sci_request_port(struct uart_port *port)
+int sci_request_port(struct uart_port *port)
{
struct resource *res;
struct sci_port *sport = to_sci_port(port);
@@ -2854,18 +2841,19 @@ static int sci_request_port(struct uart_port *port)
return 0;
}
+EXPORT_SYMBOL_NS_GPL(sci_request_port, "SH_SCI");
-static void sci_config_port(struct uart_port *port, int flags)
+void sci_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
struct sci_port *sport = to_sci_port(port);
-
- port->type = sport->cfg->type;
+ port->type = SCI_PUBLIC_PORT_ID(sport->type);
sci_request_port(port);
}
}
+EXPORT_SYMBOL_NS_GPL(sci_config_port, "SH_SCI");
-static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
+int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
{
if (ser->baud_base < 2400)
/* No paper tape reader for Mitch.. */
@@ -2873,6 +2861,76 @@ static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0;
}
+EXPORT_SYMBOL_NS_GPL(sci_verify_port, "SH_SCI");
+
+static void sci_prepare_console_write(struct uart_port *port, u32 ctrl)
+{
+ struct sci_port *s = to_sci_port(port);
+ u32 ctrl_temp =
+ s->params->param_bits->rxtx_enable |
+ (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
+ (ctrl & (SCSCR_CKE1 | SCSCR_CKE0)) |
+ s->hscif_tot;
+ sci_serial_out(port, SCSCR, ctrl_temp);
+}
+
+static void sci_console_save(struct uart_port *port)
+{
+ struct sci_port *s = to_sci_port(port);
+ struct sci_suspend_regs *regs = s->suspend_regs;
+
+ if (sci_getreg(port, SCDL)->size)
+ regs->scdl = sci_serial_in(port, SCDL);
+ if (sci_getreg(port, SCCKS)->size)
+ regs->sccks = sci_serial_in(port, SCCKS);
+ if (sci_getreg(port, SCSMR)->size)
+ regs->scsmr = sci_serial_in(port, SCSMR);
+ if (sci_getreg(port, SCSCR)->size)
+ regs->scscr = sci_serial_in(port, SCSCR);
+ if (sci_getreg(port, SCFCR)->size)
+ regs->scfcr = sci_serial_in(port, SCFCR);
+ if (sci_getreg(port, SCSPTR)->size)
+ regs->scsptr = sci_serial_in(port, SCSPTR);
+ if (sci_getreg(port, SCBRR)->size)
+ regs->scbrr = sci_serial_in(port, SCBRR);
+ if (sci_getreg(port, HSSRR)->size)
+ regs->hssrr = sci_serial_in(port, HSSRR);
+ if (sci_getreg(port, SCPCR)->size)
+ regs->scpcr = sci_serial_in(port, SCPCR);
+ if (sci_getreg(port, SCPDR)->size)
+ regs->scpdr = sci_serial_in(port, SCPDR);
+ if (sci_getreg(port, SEMR)->size)
+ regs->semr = sci_serial_in(port, SEMR);
+}
+
+static void sci_console_restore(struct uart_port *port)
+{
+ struct sci_port *s = to_sci_port(port);
+ struct sci_suspend_regs *regs = s->suspend_regs;
+
+ if (sci_getreg(port, SCDL)->size)
+ sci_serial_out(port, SCDL, regs->scdl);
+ if (sci_getreg(port, SCCKS)->size)
+ sci_serial_out(port, SCCKS, regs->sccks);
+ if (sci_getreg(port, SCSMR)->size)
+ sci_serial_out(port, SCSMR, regs->scsmr);
+ if (sci_getreg(port, SCSCR)->size)
+ sci_serial_out(port, SCSCR, regs->scscr);
+ if (sci_getreg(port, SCFCR)->size)
+ sci_serial_out(port, SCFCR, regs->scfcr);
+ if (sci_getreg(port, SCSPTR)->size)
+ sci_serial_out(port, SCSPTR, regs->scsptr);
+ if (sci_getreg(port, SCBRR)->size)
+ sci_serial_out(port, SCBRR, regs->scbrr);
+ if (sci_getreg(port, HSSRR)->size)
+ sci_serial_out(port, HSSRR, regs->hssrr);
+ if (sci_getreg(port, SCPCR)->size)
+ sci_serial_out(port, SCPCR, regs->scpcr);
+ if (sci_getreg(port, SCPDR)->size)
+ sci_serial_out(port, SCPDR, regs->scpdr);
+ if (sci_getreg(port, SEMR)->size)
+ sci_serial_out(port, SEMR, regs->semr);
+}
static const struct uart_ops sci_uart_ops = {
.tx_empty = sci_tx_empty,
@@ -2899,6 +2957,25 @@ static const struct uart_ops sci_uart_ops = {
#endif
};
+static const struct sci_port_ops sci_port_ops = {
+ .read_reg = sci_serial_in,
+ .write_reg = sci_serial_out,
+ .clear_SCxSR = sci_clear_SCxSR,
+ .transmit_chars = sci_transmit_chars,
+ .receive_chars = sci_receive_chars,
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
+ defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
+ .poll_put_char = sci_poll_put_char,
+#endif
+ .set_rtrg = scif_set_rtrg,
+ .rtrg_enabled = scif_rtrg_enabled,
+ .shutdown_complete = sci_shutdown_complete,
+ .prepare_console_write = sci_prepare_console_write,
+ .console_save = sci_console_save,
+ .console_restore = sci_console_restore,
+ .suspend_regs_size = sci_suspend_regs_size,
+};
+
static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
{
const char *clk_names[] = {
@@ -2910,14 +2987,27 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
struct clk *clk;
unsigned int i;
- if (sci_port->cfg->type == PORT_HSCIF)
+ if (sci_port->type == PORT_HSCIF) {
clk_names[SCI_SCK] = "hsck";
+ } else if (sci_port->type == SCI_PORT_RSCI) {
+ clk_names[SCI_FCK] = "operation";
+ clk_names[SCI_BRG_INT] = "bus";
+ }
for (i = 0; i < SCI_NUM_CLKS; i++) {
- clk = devm_clk_get_optional(dev, clk_names[i]);
+ const char *name = clk_names[i];
+
+ clk = devm_clk_get_optional(dev, name);
if (IS_ERR(clk))
return PTR_ERR(clk);
+ if (!clk && sci_port->type == SCI_PORT_RSCI &&
+ (i == SCI_FCK || i == SCI_BRG_INT)) {
+ return dev_err_probe(dev, -ENODEV,
+ "failed to get %s\n",
+ name);
+ }
+
if (!clk && i == SCI_FCK) {
/*
* Not all SH platforms declare a clock lookup entry
@@ -2928,13 +3018,13 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk),
"failed to get %s\n",
- clk_names[i]);
+ name);
}
if (!clk)
- dev_dbg(dev, "failed to get %s\n", clk_names[i]);
+ dev_dbg(dev, "failed to get %s\n", name);
else
- dev_dbg(dev, "clk %s is %pC rate %lu\n", clk_names[i],
+ dev_dbg(dev, "clk %s is %pC rate %lu\n", name,
clk, clk_get_rate(clk));
sci_port->clks[i] = clk;
}
@@ -2942,10 +3032,13 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
}
static const struct sci_port_params *
-sci_probe_regmap(const struct plat_sci_port *cfg)
+sci_probe_regmap(const struct plat_sci_port *cfg, struct sci_port *sci_port)
{
unsigned int regtype;
+ sci_port->ops = &sci_port_ops;
+ sci_port->port.ops = &sci_uart_ops;
+
if (cfg->regtype != SCIx_PROBE_REGTYPE)
return &sci_port_params[cfg->regtype];
@@ -2993,7 +3086,9 @@ static int sci_init_single(struct platform_device *dev,
sci_port->cfg = p;
- port->ops = &sci_uart_ops;
+ sci_port->type = p->type;
+ sci_port->regtype = p->regtype;
+
port->iotype = UPIO_MEM;
port->line = index;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_SH_SCI_CONSOLE);
@@ -3013,10 +3108,10 @@ static int sci_init_single(struct platform_device *dev,
}
/*
- * The fourth interrupt on SCI port is transmit end interrupt, so
+ * The fourth interrupt on SCI and RSCI port is transmit end interrupt, so
* shuffle the interrupts.
*/
- if (p->type == PORT_SCI)
+ if (p->type == PORT_SCI || p->type == SCI_PORT_RSCI)
swap(sci_port->irqs[SCIx_BRI_IRQ], sci_port->irqs[SCIx_TEI_IRQ]);
/* The SCI generates several interrupts. They can be muxed together or
@@ -3033,10 +3128,6 @@ static int sci_init_single(struct platform_device *dev,
for (i = 1; i < ARRAY_SIZE(sci_port->irqs); i++)
sci_port->irqs[i] = sci_port->irqs[0];
- sci_port->params = sci_probe_regmap(p);
- if (unlikely(sci_port->params == NULL))
- return -EINVAL;
-
switch (p->type) {
case PORT_SCIFB:
sci_port->rx_trigger = 48;
@@ -3054,6 +3145,9 @@ static int sci_init_single(struct platform_device *dev,
else
sci_port->rx_trigger = 8;
break;
+ case SCI_PORT_RSCI:
+ sci_port->rx_trigger = 15;
+ break;
default:
sci_port->rx_trigger = 1;
break;
@@ -3076,11 +3170,11 @@ static int sci_init_single(struct platform_device *dev,
return ret;
}
- port->type = p->type;
+ port->type = SCI_PUBLIC_PORT_ID(p->type);
port->flags = UPF_FIXED_PORT | UPF_BOOT_AUTOCONF | p->flags;
port->fifosize = sci_port->params->fifosize;
- if (port->type == PORT_SCI && !dev->dev.of_node) {
+ if (p->type == PORT_SCI && !dev->dev.of_node) {
if (sci_port->reg_size >= 0x20)
port->regshift = 2;
else
@@ -3104,7 +3198,7 @@ static int sci_init_single(struct platform_device *dev,
defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
static void serial_console_putchar(struct uart_port *port, unsigned char ch)
{
- sci_poll_put_char(port, ch);
+ to_sci_port(port)->ops->poll_put_char(port, ch);
}
/*
@@ -3116,7 +3210,9 @@ static void serial_console_write(struct console *co, const char *s,
{
struct sci_port *sci_port = &sci_ports[co->index];
struct uart_port *port = &sci_port->port;
- unsigned short bits, ctrl, ctrl_temp;
+ const struct sci_common_regs *regs = sci_port->params->common_regs;
+ unsigned int bits;
+ u32 ctrl;
unsigned long flags;
int locked = 1;
@@ -3128,21 +3224,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 = sci_serial_in(port, SCSCR);
- ctrl_temp = SCSCR_RE | SCSCR_TE |
- (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
- (ctrl & (SCSCR_CKE1 | SCSCR_CKE0));
- sci_serial_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot);
+
+ ctrl = sci_port->ops->read_reg(port, regs->control);
+ sci_port->ops->prepare_console_write(port, ctrl);
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 ((sci_serial_in(port, SCxSR) & bits) != bits)
+
+ bits = sci_port->params->param_bits->poll_sent_bits;
+
+ while ((sci_port->ops->read_reg(port, regs->status) & bits) != bits)
cpu_relax();
/* restore the SCSCR */
- sci_serial_out(port, SCSCR, ctrl);
+ sci_port->ops->write_reg(port, regs->control, ctrl);
if (locked)
uart_port_unlock_irqrestore(port, flags);
@@ -3220,13 +3316,18 @@ static struct console early_serial_console = {
static int sci_probe_earlyprintk(struct platform_device *pdev)
{
const struct plat_sci_port *cfg = dev_get_platdata(&pdev->dev);
+ struct sci_port *sp = &sci_ports[pdev->id];
if (early_serial_console.data)
return -EEXIST;
early_serial_console.index = pdev->id;
- sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true);
+ sp->params = sci_probe_regmap(cfg, sp);
+ if (!sp->params)
+ return -ENODEV;
+
+ sci_init_single(pdev, sp, pdev->id, cfg, true);
if (!strstr(early_serial_buf, "keep"))
early_serial_console.flags |= CON_BOOT;
@@ -3263,71 +3364,148 @@ static struct uart_driver sci_uart_driver = {
static void sci_remove(struct platform_device *dev)
{
- struct sci_port *port = platform_get_drvdata(dev);
- unsigned int type = port->port.type; /* uart_remove_... clears it */
+ struct sci_port *s = platform_get_drvdata(dev);
+ unsigned int type = s->type; /* uart_remove_... clears it */
- sci_ports_in_use &= ~BIT(port->port.line);
- uart_remove_one_port(&sci_uart_driver, &port->port);
+ sci_ports_in_use &= ~BIT(s->port.line);
+ uart_remove_one_port(&sci_uart_driver, &s->port);
- if (port->port.fifosize > 1)
+ if (s->port.fifosize > 1)
device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger);
- if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF)
+ if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF ||
+ type == SCI_PORT_RSCI)
device_remove_file(&dev->dev, &dev_attr_rx_fifo_timeout);
}
+static const struct sci_of_data of_sci_scif_sh2 = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SH2_SCIF_FIFODATA_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scif_rz_scifa = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_RZ_SCIFA_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_RZ_SCIFA_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scif_rzv2h = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_RZV2H_SCIF_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_RZV2H_SCIF_REGTYPE],
+};
-#define SCI_OF_DATA(type, regtype) (void *)((type) << 16 | (regtype))
-#define SCI_OF_TYPE(data) ((unsigned long)(data) >> 16)
-#define SCI_OF_REGTYPE(data) ((unsigned long)(data) & 0xffff)
+static const struct sci_of_data of_sci_rcar_scif = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SH4_SCIF_BRG_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scif_sh4 = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_SH4_SCIF_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SH4_SCIF_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scifa = {
+ .type = PORT_SCIFA,
+ .regtype = SCIx_SCIFA_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SCIFA_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scifb = {
+ .type = PORT_SCIFB,
+ .regtype = SCIx_SCIFB_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SCIFB_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_hscif = {
+ .type = PORT_HSCIF,
+ .regtype = SCIx_HSCIF_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_HSCIF_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_sci = {
+ .type = PORT_SCI,
+ .regtype = SCIx_SCI_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SCI_REGTYPE],
+};
static const struct of_device_id of_sci_match[] __maybe_unused = {
/* SoC-specific types */
{
.compatible = "renesas,scif-r7s72100",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH2_SCIF_FIFODATA_REGTYPE),
+ .data = &of_sci_scif_sh2,
},
{
.compatible = "renesas,scif-r7s9210",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
+ .data = &of_sci_scif_rz_scifa,
},
{
.compatible = "renesas,scif-r9a07g044",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
+ .data = &of_sci_scif_rz_scifa,
},
{
.compatible = "renesas,scif-r9a09g057",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZV2H_SCIF_REGTYPE),
+ .data = &of_sci_scif_rzv2h,
+ },
+#ifdef CONFIG_SERIAL_RSCI
+ {
+ .compatible = "renesas,r9a09g077-rsci",
+ .data = &of_sci_rsci_data,
},
+#endif /* CONFIG_SERIAL_RSCI */
/* Family-specific types */
{
.compatible = "renesas,rcar-gen1-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif,
}, {
.compatible = "renesas,rcar-gen2-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif,
}, {
.compatible = "renesas,rcar-gen3-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif
}, {
.compatible = "renesas,rcar-gen4-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif
+ }, {
+ .compatible = "renesas,rcar-gen5-scif",
+ .data = &of_sci_rcar_scif
},
/* Generic types */
{
.compatible = "renesas,scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_REGTYPE),
+ .data = &of_sci_scif_sh4,
}, {
.compatible = "renesas,scifa",
- .data = SCI_OF_DATA(PORT_SCIFA, SCIx_SCIFA_REGTYPE),
+ .data = &of_sci_scifa,
}, {
.compatible = "renesas,scifb",
- .data = SCI_OF_DATA(PORT_SCIFB, SCIx_SCIFB_REGTYPE),
+ .data = &of_sci_scifb,
}, {
.compatible = "renesas,hscif",
- .data = SCI_OF_DATA(PORT_HSCIF, SCIx_HSCIF_REGTYPE),
+ .data = &of_sci_hscif,
}, {
.compatible = "renesas,sci",
- .data = SCI_OF_DATA(PORT_SCI, SCIx_SCI_REGTYPE),
+ .data = &of_sci_sci,
}, {
/* Terminator */
},
@@ -3346,7 +3524,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
struct reset_control *rstc;
struct plat_sci_port *p;
struct sci_port *sp;
- const void *data;
+ const struct sci_of_data *data;
int id, ret;
if (!IS_ENABLED(CONFIG_OF) || !np)
@@ -3393,8 +3571,12 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
sp->rstc = rstc;
*dev_id = id;
- p->type = SCI_OF_TYPE(data);
- p->regtype = SCI_OF_REGTYPE(data);
+ p->type = data->type;
+ p->regtype = data->regtype;
+
+ sp->ops = data->ops;
+ sp->port.ops = data->uart_ops;
+ sp->params = data->params;
sp->has_rtscts = of_property_read_bool(np, "uart-has-rtscts");
@@ -3501,6 +3683,7 @@ static int sci_probe(struct platform_device *dev)
p = sci_parse_dt(dev, &dev_id);
if (IS_ERR(p))
return PTR_ERR(p);
+ sp = &sci_ports[dev_id];
} else {
p = dev->dev.platform_data;
if (p == NULL) {
@@ -3509,9 +3692,17 @@ static int sci_probe(struct platform_device *dev)
}
dev_id = dev->id;
+ sp = &sci_ports[dev_id];
+ sp->params = sci_probe_regmap(p, sp);
+ if (!sp->params)
+ return -ENODEV;
}
- sp = &sci_ports[dev_id];
+ sp->suspend_regs = devm_kzalloc(&dev->dev,
+ sp->ops->suspend_regs_size(),
+ GFP_KERNEL);
+ if (!sp->suspend_regs)
+ return -ENOMEM;
/*
* In case:
@@ -3543,8 +3734,8 @@ static int sci_probe(struct platform_device *dev)
if (ret)
return ret;
}
- if (sp->port.type == PORT_SCIFA || sp->port.type == PORT_SCIFB ||
- sp->port.type == PORT_HSCIF) {
+ if (sp->type == PORT_SCIFA || sp->type == PORT_SCIFB ||
+ sp->type == PORT_HSCIF || sp->type == SCI_PORT_RSCI) {
ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_timeout);
if (ret) {
if (sp->port.fifosize > 1) {
@@ -3563,73 +3754,17 @@ static int sci_probe(struct platform_device *dev)
return 0;
}
-static void sci_console_save(struct sci_port *s)
-{
- struct sci_suspend_regs *regs = &s->suspend_regs;
- struct uart_port *port = &s->port;
-
- if (sci_getreg(port, SCDL)->size)
- regs->scdl = sci_serial_in(port, SCDL);
- if (sci_getreg(port, SCCKS)->size)
- regs->sccks = sci_serial_in(port, SCCKS);
- if (sci_getreg(port, SCSMR)->size)
- regs->scsmr = sci_serial_in(port, SCSMR);
- if (sci_getreg(port, SCSCR)->size)
- regs->scscr = sci_serial_in(port, SCSCR);
- if (sci_getreg(port, SCFCR)->size)
- regs->scfcr = sci_serial_in(port, SCFCR);
- if (sci_getreg(port, SCSPTR)->size)
- regs->scsptr = sci_serial_in(port, SCSPTR);
- if (sci_getreg(port, SCBRR)->size)
- regs->scbrr = sci_serial_in(port, SCBRR);
- if (sci_getreg(port, HSSRR)->size)
- regs->hssrr = sci_serial_in(port, HSSRR);
- if (sci_getreg(port, SCPCR)->size)
- regs->scpcr = sci_serial_in(port, SCPCR);
- if (sci_getreg(port, SCPDR)->size)
- regs->scpdr = sci_serial_in(port, SCPDR);
- if (sci_getreg(port, SEMR)->size)
- regs->semr = sci_serial_in(port, SEMR);
-}
-
-static void sci_console_restore(struct sci_port *s)
-{
- struct sci_suspend_regs *regs = &s->suspend_regs;
- struct uart_port *port = &s->port;
-
- if (sci_getreg(port, SCDL)->size)
- sci_serial_out(port, SCDL, regs->scdl);
- if (sci_getreg(port, SCCKS)->size)
- sci_serial_out(port, SCCKS, regs->sccks);
- if (sci_getreg(port, SCSMR)->size)
- sci_serial_out(port, SCSMR, regs->scsmr);
- if (sci_getreg(port, SCSCR)->size)
- sci_serial_out(port, SCSCR, regs->scscr);
- if (sci_getreg(port, SCFCR)->size)
- sci_serial_out(port, SCFCR, regs->scfcr);
- if (sci_getreg(port, SCSPTR)->size)
- sci_serial_out(port, SCSPTR, regs->scsptr);
- if (sci_getreg(port, SCBRR)->size)
- sci_serial_out(port, SCBRR, regs->scbrr);
- if (sci_getreg(port, HSSRR)->size)
- sci_serial_out(port, HSSRR, regs->hssrr);
- if (sci_getreg(port, SCPCR)->size)
- sci_serial_out(port, SCPCR, regs->scpcr);
- if (sci_getreg(port, SCPDR)->size)
- sci_serial_out(port, SCPDR, regs->scpdr);
- if (sci_getreg(port, SEMR)->size)
- sci_serial_out(port, SEMR, regs->semr);
-}
-
-static __maybe_unused int sci_suspend(struct device *dev)
+static int sci_suspend(struct device *dev)
{
struct sci_port *sport = dev_get_drvdata(dev);
if (sport) {
uart_suspend_port(&sci_uart_driver, &sport->port);
- if (!console_suspend_enabled && uart_console(&sport->port))
- sci_console_save(sport);
+ if (!console_suspend_enabled && uart_console(&sport->port)) {
+ if (sport->ops->console_save)
+ sport->ops->console_save(&sport->port);
+ }
else
return reset_control_assert(sport->rstc);
}
@@ -3637,13 +3772,14 @@ static __maybe_unused int sci_suspend(struct device *dev)
return 0;
}
-static __maybe_unused int sci_resume(struct device *dev)
+static int sci_resume(struct device *dev)
{
struct sci_port *sport = dev_get_drvdata(dev);
if (sport) {
if (!console_suspend_enabled && uart_console(&sport->port)) {
- sci_console_restore(sport);
+ if (sport->ops->console_restore)
+ sport->ops->console_restore(&sport->port);
} else {
int ret = reset_control_deassert(sport->rstc);
@@ -3657,14 +3793,14 @@ static __maybe_unused int sci_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(sci_dev_pm_ops, sci_suspend, sci_resume);
+static DEFINE_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",
- .pm = &sci_dev_pm_ops,
+ .pm = pm_sleep_ptr(&sci_dev_pm_ops),
.of_match_table = of_match_ptr(of_sci_match),
},
};
@@ -3707,21 +3843,34 @@ static int early_console_exit(struct console *co)
return 0;
}
-static int __init early_console_setup(struct earlycon_device *device,
- int type)
+int __init scix_early_console_setup(struct earlycon_device *device,
+ const struct sci_of_data *data)
{
+ const struct sci_common_regs *regs;
+
if (!device->port.membase)
return -ENODEV;
- device->port.type = type;
+ device->port.type = SCI_PUBLIC_PORT_ID(data->type);
+
sci_ports[0].port = device->port;
- port_cfg.type = type;
+ sci_ports[0].type = data->type;
+ sci_ports[0].regtype = data->regtype;
+
+ port_cfg.type = data->type;
+ port_cfg.regtype = data->regtype;
+
sci_ports[0].cfg = &port_cfg;
- sci_ports[0].params = sci_probe_regmap(&port_cfg);
+ sci_ports[0].params = data->params;
+ sci_ports[0].ops = data->ops;
+ sci_ports[0].port.ops = data->uart_ops;
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);
+ regs = sci_ports[0].params->common_regs;
+
+ port_cfg.scscr = sci_ports[0].ops->read_reg(&sci_ports[0].port, regs->control);
+ sci_ports[0].ops->write_reg(&sci_ports[0].port,
+ regs->control,
+ sci_ports[0].params->param_bits->rxtx_enable | port_cfg.scscr);
device->con->write = serial_console_write;
device->con->exit = early_console_exit;
@@ -3731,41 +3880,39 @@ static int __init early_console_setup(struct earlycon_device *device,
static int __init sci_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCI);
+ return scix_early_console_setup(device, &of_sci_sci);
}
static int __init scif_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCIF);
+ return scix_early_console_setup(device, &of_sci_scif_sh4);
}
static int __init rzscifa_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- port_cfg.regtype = SCIx_RZ_SCIFA_REGTYPE;
- return early_console_setup(device, PORT_SCIF);
+ return scix_early_console_setup(device, &of_sci_scif_rz_scifa);
}
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);
+ return scix_early_console_setup(device, &of_sci_scif_rzv2h);
}
static int __init scifa_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCIFA);
+ return scix_early_console_setup(device, &of_sci_scifa);
}
static int __init scifb_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCIFB);
+ return scix_early_console_setup(device, &of_sci_scifb);
}
static int __init hscif_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_HSCIF);
+ return scix_early_console_setup(device, &of_sci_hscif);
}
OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index 0b65563c4e9e..951681aba586 100644
--- a/drivers/tty/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
@@ -32,8 +32,6 @@ enum {
HSRTRGR, /* Rx FIFO Data Count Trigger Register */
HSTTRGR, /* Tx FIFO Data Count Trigger Register */
SEMR, /* Serial extended mode register */
-
- SCIx_NR_REGS,
};
diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
index 054a8e630ace..110d67613192 100644
--- a/drivers/tty/serial/sifive.c
+++ b/drivers/tty/serial/sifive.c
@@ -141,6 +141,7 @@
* @baud_rate: UART serial line rate (e.g., 115200 baud)
* @clk: reference to this device's clock
* @clk_notifier: clock rate change notifier for upstream clock changes
+ * @console_line_ended: indicate that the console line is fully written
*
* Configuration data specific to this SiFive UART.
*/
@@ -151,6 +152,7 @@ struct sifive_serial_port {
unsigned long baud_rate;
struct clk *clk;
struct notifier_block clk_notifier;
+ bool console_line_ended;
};
/*
@@ -785,33 +787,88 @@ static void sifive_serial_console_putchar(struct uart_port *port, unsigned char
__ssp_wait_for_xmitr(ssp);
__ssp_transmit_char(ssp, ch);
+
+ ssp->console_line_ended = (ch == '\n');
+}
+
+static void sifive_serial_device_lock(struct console *co, unsigned long *flags)
+{
+ struct uart_port *up = &sifive_serial_console_ports[co->index]->port;
+
+ __uart_port_lock_irqsave(up, flags);
+}
+
+static void sifive_serial_device_unlock(struct console *co, unsigned long flags)
+{
+ struct uart_port *up = &sifive_serial_console_ports[co->index]->port;
+
+ __uart_port_unlock_irqrestore(up, flags);
}
-static void sifive_serial_console_write(struct console *co, const char *s,
- unsigned int count)
+static void sifive_serial_console_write_atomic(struct console *co,
+ struct nbcon_write_context *wctxt)
{
struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index];
- unsigned long flags;
+ struct uart_port *port = &ssp->port;
unsigned int ier;
- int locked = 1;
if (!ssp)
return;
- if (oops_in_progress)
- locked = uart_port_trylock_irqsave(&ssp->port, &flags);
- else
- uart_port_lock_irqsave(&ssp->port, &flags);
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
__ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
- uart_console_write(&ssp->port, s, count, sifive_serial_console_putchar);
+ if (!ssp->console_line_ended)
+ uart_console_write(port, "\n", 1, sifive_serial_console_putchar);
+ uart_console_write(port, wctxt->outbuf, wctxt->len,
+ sifive_serial_console_putchar);
__ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp);
- if (locked)
- uart_port_unlock_irqrestore(&ssp->port, flags);
+ nbcon_exit_unsafe(wctxt);
+}
+
+static void sifive_serial_console_write_thread(struct console *co,
+ struct nbcon_write_context *wctxt)
+{
+ struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index];
+ struct uart_port *port = &ssp->port;
+ unsigned int ier;
+
+ if (!ssp)
+ return;
+
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
+
+ ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
+ __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
+
+ if (nbcon_exit_unsafe(wctxt)) {
+ int len = READ_ONCE(wctxt->len);
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (!nbcon_enter_unsafe(wctxt))
+ break;
+
+ uart_console_write(port, wctxt->outbuf + i, 1,
+ sifive_serial_console_putchar);
+
+ if (!nbcon_exit_unsafe(wctxt))
+ break;
+ }
+ }
+
+ while (!nbcon_enter_unsafe(wctxt))
+ nbcon_reacquire_nobuf(wctxt);
+
+ __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp);
+
+ nbcon_exit_unsafe(wctxt);
}
static int sifive_serial_console_setup(struct console *co, char *options)
@@ -829,6 +886,8 @@ static int sifive_serial_console_setup(struct console *co, char *options)
if (!ssp)
return -ENODEV;
+ ssp->console_line_ended = true;
+
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -839,10 +898,13 @@ static struct uart_driver sifive_serial_uart_driver;
static struct console sifive_serial_console = {
.name = SIFIVE_TTY_PREFIX,
- .write = sifive_serial_console_write,
+ .write_atomic = sifive_serial_console_write_atomic,
+ .write_thread = sifive_serial_console_write_thread,
+ .device_lock = sifive_serial_device_lock,
+ .device_unlock = sifive_serial_device_unlock,
.device = uart_console_device,
.setup = sifive_serial_console_setup,
- .flags = CON_PRINTBUFFER,
+ .flags = CON_PRINTBUFFER | CON_NBCON,
.index = -1,
.data = &sifive_serial_uart_driver,
};
diff --git a/drivers/tty/serial/tegra-utc.c b/drivers/tty/serial/tegra-utc.c
index 39b14fe813c9..0c70d3e7b9b9 100644
--- a/drivers/tty/serial/tegra-utc.c
+++ b/drivers/tty/serial/tegra-utc.c
@@ -434,7 +434,7 @@ static void tegra_utc_console_write_atomic(struct console *cons, struct nbcon_wr
outbuf += burst_size;
len -= burst_size;
- };
+ }
nbcon_exit_unsafe(wctxt);
}
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index a41e7fc373b7..39c1fd1ff9ce 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -880,16 +880,6 @@ of_err:
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- if (!ulite_uart_driver.state) {
- dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
- ret = uart_register_driver(&ulite_uart_driver);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to register driver\n");
- clk_disable_unprepare(pdata->clk);
- return ret;
- }
- }
-
ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
pm_runtime_mark_last_busy(&pdev->dev);
@@ -929,16 +919,25 @@ static struct platform_driver ulite_platform_driver = {
static int __init ulite_init(void)
{
+ int ret;
+
+ pr_debug("uartlite: calling uart_register_driver()\n");
+ ret = uart_register_driver(&ulite_uart_driver);
+ if (ret)
+ return ret;
pr_debug("uartlite: calling platform_driver_register()\n");
- return platform_driver_register(&ulite_platform_driver);
+ ret = platform_driver_register(&ulite_platform_driver);
+ if (ret)
+ uart_unregister_driver(&ulite_uart_driver);
+
+ return ret;
}
static void __exit ulite_exit(void)
{
platform_driver_unregister(&ulite_platform_driver);
- if (ulite_uart_driver.state)
- uart_unregister_driver(&ulite_uart_driver);
+ uart_unregister_driver(&ulite_uart_driver);
}
module_init(ulite_init);