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.h8
-rw-r--r--drivers/tty/serial/8250/8250_ce4100.c93
-rw-r--r--drivers/tty/serial/8250/8250_core.c318
-rw-r--r--drivers/tty/serial/8250/8250_dw.c36
-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.c56
-rw-r--r--drivers/tty/serial/8250/8250_omap.c53
-rw-r--r--drivers/tty/serial/8250/8250_pci.c6
-rw-r--r--drivers/tty/serial/8250/8250_port.c774
-rw-r--r--drivers/tty/serial/8250/8250_rsa.c96
-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/Makefile3
-rw-r--r--drivers/tty/serial/Kconfig7
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/fsl_lpuart.c8
-rw-r--r--drivers/tty/serial/imx.c17
-rw-r--r--drivers/tty/serial/pch_uart.c2
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c395
-rw-r--r--drivers/tty/serial/rsci.c480
-rw-r--r--drivers/tty/serial/rsci.h10
-rw-r--r--drivers/tty/serial/serial_base_bus.c4
-rw-r--r--drivers/tty/serial/serial_core.c78
-rw-r--r--drivers/tty/serial/sh-sci-common.h8
-rw-r--r--drivers/tty/serial/sh-sci.c223
28 files changed, 1824 insertions, 878 deletions
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 18530c31a598..cfe6ba286b45 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -318,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_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 7a6050f1c094..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;
@@ -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_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 b0e44fb00b3a..cb5b42b3609c 100644
--- a/drivers/tty/serial/8250/8250_ni.c
+++ b/drivers/tty/serial/8250/8250_ni.c
@@ -275,76 +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;
struct ni16550_data *data;
+ unsigned int prescaler;
const char *portmode;
bool rs232_property;
int ret;
+ 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);
- 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.flags = 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-frequency" ACPI
*/
- uart.port.uartclk = info->uartclk;
+ uart->port.uartclk = info->uartclk;
- ret = uart_read_port_properties(&uart.port);
+ ret = uart_read_port_properties(&uart->port);
if (ret)
return ret;
- if (!uart.port.uartclk) {
+ 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)
+ if (!uart->port.uartclk)
return dev_err_probe(dev, -ENODEV, "unable to determine clock frequency!\n");
prescaler = info->prescaler;
device_property_read_u32(dev, "clock-prescaler", &prescaler);
if (prescaler) {
- uart.port.set_mctrl = ni16550_set_mctrl;
- ni16550_config_prescaler(&uart, (u8)prescaler);
+ uart->port.set_mctrl = ni16550_set_mctrl;
+ ni16550_config_prescaler(uart, (u8)prescaler);
}
/*
@@ -362,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");
@@ -377,10 +381,10 @@ 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)
return ret;
data->line = ret;
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 72ae08d6204f..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);
@@ -1310,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;
@@ -1332,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_port.c b/drivers/tty/serial/8250/8250_port.c
index 6d7b8c4667c9..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)
{
}
@@ -705,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)
@@ -713,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.
@@ -885,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;
@@ -910,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) {
@@ -997,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 {
@@ -1010,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;
@@ -1023,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;
}
@@ -1086,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;
@@ -1116,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);
@@ -1158,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.
@@ -1207,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;
}
}
@@ -1231,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;
}
}
@@ -1267,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);
@@ -1283,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);
/*
@@ -1311,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)
@@ -1354,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);
@@ -2190,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
*
@@ -2227,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
*
@@ -2246,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;
@@ -2521,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
@@ -2555,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);
@@ -2618,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,
@@ -2744,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)
@@ -2810,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;
@@ -2845,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);
diff --git a/drivers/tty/serial/8250/8250_rsa.c b/drivers/tty/serial/8250/8250_rsa.c
index 4c8b9671bd41..d34093cc03ad 100644
--- a/drivers/tty/serial/8250/8250_rsa.c
+++ b/drivers/tty/serial/8250/8250_rsa.c
@@ -107,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/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/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 2790b4078e7e..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,
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index bd02ee898f5d..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 {
@@ -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/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 0293b6210aa6..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>
@@ -99,10 +100,16 @@
#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 {
@@ -140,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;
@@ -192,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);
@@ -664,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,
@@ -1071,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)
@@ -1283,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 */
@@ -1317,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",
@@ -1339,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);
@@ -1406,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
@@ -1588,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 = {
@@ -1690,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;
@@ -1709,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);
@@ -1745,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);
@@ -1764,13 +1944,19 @@ 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,
@@ -1779,11 +1965,15 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
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)
@@ -1796,6 +1986,31 @@ static void qcom_geni_serial_remove(struct platform_device *pdev)
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)
@@ -1833,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)
};
@@ -1850,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/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 1f7708a91fc6..86d404d649a3 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -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);
/*
@@ -2028,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
@@ -2050,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)) \
@@ -2132,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)
@@ -2553,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,
@@ -2561,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,
@@ -2960,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,
@@ -2970,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,
@@ -2990,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,
@@ -3010,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,
@@ -3146,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;
@@ -3185,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);
}
@@ -3209,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);
@@ -3228,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
diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci-common.h
index bd9d9cfac1c8..e3c028df14f1 100644
--- a/drivers/tty/serial/sh-sci-common.h
+++ b/drivers/tty/serial/sh-sci-common.h
@@ -5,6 +5,11 @@
#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 */
@@ -142,6 +147,9 @@ struct sci_port {
int rx_fifo_timeout;
u16 hscif_tot;
+ u8 type;
+ u8 regtype;
+
const struct sci_port_ops *ops;
bool has_rtscts;
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 1c356544a832..538b2f991609 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -54,6 +54,7 @@
#include <asm/platform_early.h>
#endif
+#include "rsci.h"
#include "serial_mctrl_gpio.h"
#include "sh-sci.h"
#include "sh-sci-common.h"
@@ -75,6 +76,8 @@
#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;
@@ -548,6 +551,7 @@ 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");
void sci_port_disable(struct sci_port *sci_port)
{
@@ -561,6 +565,7 @@ 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)
{
@@ -580,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;
@@ -592,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]);
@@ -601,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);
@@ -611,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);
@@ -620,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;
@@ -633,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);
@@ -655,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);
@@ -669,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);
@@ -742,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;
@@ -765,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 */
@@ -852,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);
@@ -873,7 +883,7 @@ static void sci_transmit_chars(struct uart_port *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;
@@ -904,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;
@@ -914,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 {
@@ -1052,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)
@@ -1065,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;
@@ -1150,7 +1161,7 @@ static ssize_t rx_fifo_trigger_store(struct device *dev,
return ret;
sci->rx_trigger = sci->ops->set_rtrg(port, r);
- if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+ if (sci->type == PORT_SCIFA || sci->type == PORT_SCIFB)
sci->ops->set_rtrg(port, 1);
return count;
@@ -1166,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;
@@ -1188,7 +1199,7 @@ 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;
@@ -1229,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]);
@@ -1315,10 +1326,10 @@ 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)
+ if (s->regtype == SCIx_RZ_SCIFA_REGTYPE)
s->ops->set_rtrg(port, s->rx_trigger);
else
scr &= ~SCSCR_RDRQE;
@@ -1558,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);
@@ -1682,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);
}
}
@@ -1753,10 +1764,10 @@ 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) {
+ if (s->regtype == SCIx_RZ_SCIFA_REGTYPE) {
s->ops->set_rtrg(port, 1);
scr |= SCSCR_RIE;
} else {
@@ -1820,7 +1831,7 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
unsigned long flags;
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);
@@ -1867,7 +1878,7 @@ 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);
@@ -2091,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 */
@@ -2118,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) {
@@ -2164,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 {
@@ -2277,6 +2292,7 @@ int sci_startup(struct uart_port *port)
return 0;
}
+EXPORT_SYMBOL_NS_GPL(sci_startup, "SH_SCI");
void sci_shutdown(struct uart_port *port)
{
@@ -2289,8 +2305,8 @@ 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);
+ s->port.ops->stop_rx(port);
+ s->port.ops->stop_tx(port);
s->ops->shutdown_complete(port);
uart_port_unlock_irqrestore(port, flags);
@@ -2307,6 +2323,7 @@ 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)
@@ -2315,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) {
@@ -2342,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) {
@@ -2375,7 +2392,7 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
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;
/*
@@ -2460,8 +2477,8 @@ static void sci_reset(struct uart_port *port)
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)
+ if (s->type == PORT_SCIFA ||
+ s->type == PORT_SCIFB)
s->ops->set_rtrg(port, 1);
else
s->ops->set_rtrg(port, s->rx_trigger);
@@ -2521,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;
@@ -2607,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;
@@ -2692,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.
@@ -2738,10 +2755,13 @@ 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:
@@ -2798,6 +2818,7 @@ 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");
int sci_request_port(struct uart_port *port)
{
@@ -2820,16 +2841,17 @@ int sci_request_port(struct uart_port *port)
return 0;
}
+EXPORT_SYMBOL_NS_GPL(sci_request_port, "SH_SCI");
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");
int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
{
@@ -2839,6 +2861,7 @@ 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)
{
@@ -2964,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
@@ -2982,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;
}
@@ -3050,6 +3086,9 @@ static int sci_init_single(struct platform_device *dev,
sci_port->cfg = p;
+ 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);
@@ -3069,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
@@ -3106,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;
@@ -3128,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
@@ -3322,15 +3364,16 @@ 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);
}
@@ -3424,6 +3467,12 @@ static const struct of_device_id of_sci_match[] __maybe_unused = {
.compatible = "renesas,scif-r9a09g057",
.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",
@@ -3437,6 +3486,9 @@ static const struct of_device_id of_sci_match[] __maybe_unused = {
}, {
.compatible = "renesas,rcar-gen4-scif",
.data = &of_sci_rcar_scif
+ }, {
+ .compatible = "renesas,rcar-gen5-scif",
+ .data = &of_sci_rcar_scif
},
/* Generic types */
{
@@ -3682,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) {
@@ -3702,7 +3754,7 @@ static int sci_probe(struct platform_device *dev)
return 0;
}
-static __maybe_unused int sci_suspend(struct device *dev)
+static int sci_suspend(struct device *dev)
{
struct sci_port *sport = dev_get_drvdata(dev);
@@ -3720,7 +3772,7 @@ 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);
@@ -3741,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),
},
};
@@ -3799,8 +3851,11 @@ int __init scix_early_console_setup(struct earlycon_device *device,
if (!device->port.membase)
return -ENODEV;
- device->port.type = data->type;
+ device->port.type = SCI_PUBLIC_PORT_ID(data->type);
+
sci_ports[0].port = device->port;
+ sci_ports[0].type = data->type;
+ sci_ports[0].regtype = data->regtype;
port_cfg.type = data->type;
port_cfg.regtype = data->regtype;