TTY/Serial patches for 4.18-rc1

Here is the big tty/serial driver update for 4.18-rc1.
 
 There's nothing major here, just lots of serial driver updates.  Full
 details are in the shortlog, nothing anything specific to call out here.
 
 All have been in linux-next for a while with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWxbZzQ8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ym2pQCggrWJsOeXLXgzhVDH6/qMFP9R/hEAoLTvmOWQ
 BlPIlvRDm/ud33VogJ8t
 =XS8u
 -----END PGP SIGNATURE-----

Merge tag 'tty-4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial updates from Greg KH:
 "Here is the big tty/serial driver update for 4.18-rc1.

  There's nothing major here, just lots of serial driver updates. Full
  details are in the shortlog, nothing anything specific to call out
  here.

  All have been in linux-next for a while with no reported issues"

* tag 'tty-4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (55 commits)
  vt: Perform safe console erase only once
  serial: imx: disable UCR4_OREN on shutdown
  serial: imx: drop CTS/RTS handling from shutdown
  tty: fix typo in ASYNCB_FOURPORT comment
  serial: samsung: check DMA engine capabilities before using DMA mode
  tty: Fix data race in tty_insert_flip_string_fixed_flag
  tty: serial: msm_geni_serial: Fix TX infinite loop
  serial: 8250_dw: Fix runtime PM handling
  serial: 8250: omap: Fix idling of clocks for unused uarts
  tty: serial: drop ATH79 specific SoC symbols
  serial: 8250: Add missing rxtrig_bytes on Altera 16550 UART
  serial/aspeed-vuart: fix a couple mod_timer() calls
  serial: sh-sci: Use spin_{try}lock_irqsave instead of open coding version
  serial: 8250_of: Add IO space support
  tty/serial: atmel: use port->name as name in request_irq()
  serial: imx: dma_unmap_sg buffers on shutdown
  serial: imx: cleanup imx_uart_disable_dma()
  tty: serial: qcom_geni_serial: Add early console support
  tty: serial: qcom_geni_serial: Return IRQ_NONE for spurious interrupts
  tty: serial: qcom_geni_serial: Use iowrite32_rep to write to FIFO
  ...
This commit is contained in:
Linus Torvalds 2018-06-05 16:55:56 -07:00
commit a22e48cf31
31 changed files with 693 additions and 296 deletions

View File

@ -1020,6 +1020,12 @@
address. The serial port must already be setup address. The serial port must already be setup
and configured. Options are not yet supported. and configured. Options are not yet supported.
qcom_geni,<addr>
Start an early, polled-mode console on a Qualcomm
Generic Interface (GENI) based serial port at the
specified address. The serial port must already be
setup and configured. Options are not yet supported.
earlyprintk= [X86,SH,ARM,M68k,S390] earlyprintk= [X86,SH,ARM,M68k,S390]
earlyprintk=vga earlyprintk=vga
earlyprintk=efi earlyprintk=efi

View File

@ -163,7 +163,7 @@
}; };
uart0: serial@12000 { uart0: serial@12000 {
compatible = "snps,dw-apb-uart"; compatible = "marvell,armada-38x-uart";
reg = <0x12000 0x100>; reg = <0x12000 0x100>;
reg-shift = <2>; reg-shift = <2>;
interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
@ -173,7 +173,7 @@
}; };
uart1: serial@12100 { uart1: serial@12100 {
compatible = "snps,dw-apb-uart"; compatible = "marvell,armada-38x-uart";
reg = <0x12100 0x100>; reg = <0x12100 0x100>;
reg-shift = <2>; reg-shift = <2>;
interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;

View File

@ -416,7 +416,7 @@ void ipwireless_network_packet_received(struct ipw_network *network,
struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw) struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw)
{ {
struct ipw_network *network = struct ipw_network *network =
kzalloc(sizeof(struct ipw_network), GFP_ATOMIC); kzalloc(sizeof(struct ipw_network), GFP_KERNEL);
if (!network) if (!network)
return NULL; return NULL;

View File

@ -2675,7 +2675,7 @@ static inline void muxnet_put(struct gsm_mux_net *mux_net)
kref_put(&mux_net->ref, net_free); kref_put(&mux_net->ref, net_free);
} }
static int gsm_mux_net_start_xmit(struct sk_buff *skb, static netdev_tx_t gsm_mux_net_start_xmit(struct sk_buff *skb,
struct net_device *net) struct net_device *net)
{ {
struct gsm_mux_net *mux_net = netdev_priv(net); struct gsm_mux_net *mux_net = netdev_priv(net);

View File

@ -72,19 +72,19 @@ do { \
#define TMP_BUF_MAX 256 #define TMP_BUF_MAX 256
#define DUMP(buf__,len__) \ #define DUMP(buf__, len__) \
do { \ do { \
char tbuf[TMP_BUF_MAX] = {0};\ char tbuf[TMP_BUF_MAX] = {0}; \
if (len__ > 1) {\ if (len__ > 1) { \
snprintf(tbuf, len__ > TMP_BUF_MAX ? TMP_BUF_MAX : len__, "%s", buf__);\ u32 data_len = min_t(u32, len__, TMP_BUF_MAX); \
if (tbuf[len__-2] == '\r') {\ strscpy(tbuf, buf__, data_len); \
tbuf[len__-2] = 'r';\ if (tbuf[data_len - 2] == '\r') \
} \ tbuf[data_len - 2] = 'r'; \
DBG1("SENDING: '%s' (%d+n)", tbuf, len__);\ DBG1("SENDING: '%s' (%d+n)", tbuf, len__); \
} else {\ } else { \
DBG1("SENDING: '%s' (%d)", tbuf, len__);\ DBG1("SENDING: '%s' (%d)", tbuf, len__); \
} \ } \
} while (0) } while (0)
/* Defines */ /* Defines */
#define NOZOMI_NAME "nozomi" #define NOZOMI_NAME "nozomi"
@ -102,41 +102,41 @@ do { \
#define RECEIVE_BUF_MAX 4 #define RECEIVE_BUF_MAX 4
#define R_IIR 0x0000 /* Interrupt Identity Register */ #define R_IIR 0x0000 /* Interrupt Identity Register */
#define R_FCR 0x0000 /* Flow Control Register */ #define R_FCR 0x0000 /* Flow Control Register */
#define R_IER 0x0004 /* Interrupt Enable Register */ #define R_IER 0x0004 /* Interrupt Enable Register */
#define NOZOMI_CONFIG_MAGIC 0xEFEFFEFE #define NOZOMI_CONFIG_MAGIC 0xEFEFFEFE
#define TOGGLE_VALID 0x0000 #define TOGGLE_VALID 0x0000
/* Definition of interrupt tokens */ /* Definition of interrupt tokens */
#define MDM_DL1 0x0001 #define MDM_DL1 0x0001
#define MDM_UL1 0x0002 #define MDM_UL1 0x0002
#define MDM_DL2 0x0004 #define MDM_DL2 0x0004
#define MDM_UL2 0x0008 #define MDM_UL2 0x0008
#define DIAG_DL1 0x0010 #define DIAG_DL1 0x0010
#define DIAG_DL2 0x0020 #define DIAG_DL2 0x0020
#define DIAG_UL 0x0040 #define DIAG_UL 0x0040
#define APP1_DL 0x0080 #define APP1_DL 0x0080
#define APP1_UL 0x0100 #define APP1_UL 0x0100
#define APP2_DL 0x0200 #define APP2_DL 0x0200
#define APP2_UL 0x0400 #define APP2_UL 0x0400
#define CTRL_DL 0x0800 #define CTRL_DL 0x0800
#define CTRL_UL 0x1000 #define CTRL_UL 0x1000
#define RESET 0x8000 #define RESET 0x8000
#define MDM_DL (MDM_DL1 | MDM_DL2) #define MDM_DL (MDM_DL1 | MDM_DL2)
#define MDM_UL (MDM_UL1 | MDM_UL2) #define MDM_UL (MDM_UL1 | MDM_UL2)
#define DIAG_DL (DIAG_DL1 | DIAG_DL2) #define DIAG_DL (DIAG_DL1 | DIAG_DL2)
/* modem signal definition */ /* modem signal definition */
#define CTRL_DSR 0x0001 #define CTRL_DSR 0x0001
#define CTRL_DCD 0x0002 #define CTRL_DCD 0x0002
#define CTRL_RI 0x0004 #define CTRL_RI 0x0004
#define CTRL_CTS 0x0008 #define CTRL_CTS 0x0008
#define CTRL_DTR 0x0001 #define CTRL_DTR 0x0001
#define CTRL_RTS 0x0002 #define CTRL_RTS 0x0002
#define MAX_PORT 4 #define MAX_PORT 4
#define NOZOMI_MAX_PORTS 5 #define NOZOMI_MAX_PORTS 5
@ -155,7 +155,7 @@ enum card_type {
/* Initialization states a card can be in */ /* Initialization states a card can be in */
enum card_state { enum card_state {
NOZOMI_STATE_UKNOWN = 0, NOZOMI_STATE_UNKNOWN = 0,
NOZOMI_STATE_ENABLED = 1, /* pci device enabled */ NOZOMI_STATE_ENABLED = 1, /* pci device enabled */
NOZOMI_STATE_ALLOCATED = 2, /* config setup done */ NOZOMI_STATE_ALLOCATED = 2, /* config setup done */
NOZOMI_STATE_READY = 3, /* flowcontrols received */ NOZOMI_STATE_READY = 3, /* flowcontrols received */
@ -365,7 +365,7 @@ struct buffer {
u8 *data; u8 *data;
} __attribute__ ((packed)); } __attribute__ ((packed));
/* Global variables */ /* Global variables */
static const struct pci_device_id nozomi_pci_tbl[] = { static const struct pci_device_id nozomi_pci_tbl[] = {
{PCI_DEVICE(0x1931, 0x000c)}, /* Nozomi HSDPA */ {PCI_DEVICE(0x1931, 0x000c)}, /* Nozomi HSDPA */
{}, {},
@ -1686,12 +1686,12 @@ static int ntty_tiocmget(struct tty_struct *tty)
/* Note: these could change under us but it is not clear this /* Note: these could change under us but it is not clear this
matters if so */ matters if so */
return (ctrl_ul->RTS ? TIOCM_RTS : 0) | return (ctrl_ul->RTS ? TIOCM_RTS : 0)
(ctrl_ul->DTR ? TIOCM_DTR : 0) | | (ctrl_ul->DTR ? TIOCM_DTR : 0)
(ctrl_dl->DCD ? TIOCM_CAR : 0) | | (ctrl_dl->DCD ? TIOCM_CAR : 0)
(ctrl_dl->RI ? TIOCM_RNG : 0) | | (ctrl_dl->RI ? TIOCM_RNG : 0)
(ctrl_dl->DSR ? TIOCM_DSR : 0) | | (ctrl_dl->DSR ? TIOCM_DSR : 0)
(ctrl_dl->CTS ? TIOCM_CTS : 0); | (ctrl_dl->CTS ? TIOCM_CTS : 0);
} }
/* Sets io controls parameters */ /* Sets io controls parameters */
@ -1722,10 +1722,10 @@ static int ntty_cflags_changed(struct port *port, unsigned long flags,
const struct async_icount cnow = port->tty_icount; const struct async_icount cnow = port->tty_icount;
int ret; int ret;
ret = ((flags & TIOCM_RNG) && (cnow.rng != cprev->rng)) || ret = ((flags & TIOCM_RNG) && (cnow.rng != cprev->rng))
((flags & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || || ((flags & TIOCM_DSR) && (cnow.dsr != cprev->dsr))
((flags & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || || ((flags & TIOCM_CD) && (cnow.dcd != cprev->dcd))
((flags & TIOCM_CTS) && (cnow.cts != cprev->cts)); || ((flags & TIOCM_CTS) && (cnow.cts != cprev->cts));
*cprev = cnow; *cprev = cnow;

View File

@ -110,16 +110,19 @@ static void pty_unthrottle(struct tty_struct *tty)
static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
{ {
struct tty_struct *to = tty->link; struct tty_struct *to = tty->link;
unsigned long flags;
if (tty->stopped) if (tty->stopped)
return 0; return 0;
if (c > 0) { if (c > 0) {
spin_lock_irqsave(&to->port->lock, flags);
/* Stuff the data into the input queue of the other end */ /* Stuff the data into the input queue of the other end */
c = tty_insert_flip_string(to->port, buf, c); c = tty_insert_flip_string(to->port, buf, c);
/* And shovel */ /* And shovel */
if (c) if (c)
tty_flip_buffer_push(to->port); tty_flip_buffer_push(to->port);
spin_unlock_irqrestore(&to->port->lock, flags);
} }
return c; return c;
} }

View File

@ -10,6 +10,8 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/clk.h> #include <linux/clk.h>
#include "8250.h" #include "8250.h"
@ -28,8 +30,17 @@ struct aspeed_vuart {
void __iomem *regs; void __iomem *regs;
struct clk *clk; struct clk *clk;
int line; int line;
struct timer_list unthrottle_timer;
struct uart_8250_port *port;
}; };
/*
* If we fill the tty flip buffers, we throttle the data ready interrupt
* to prevent dropped characters. This timeout defines how long we wait
* to (conditionally, depending on buffer state) unthrottle.
*/
static const int unthrottle_timeout = HZ/10;
/* /*
* The VUART is basically two UART 'front ends' connected by their FIFO * The VUART is basically two UART 'front ends' connected by their FIFO
* (no actual serial line in between). One is on the BMC side (management * (no actual serial line in between). One is on the BMC side (management
@ -179,6 +190,114 @@ static void aspeed_vuart_shutdown(struct uart_port *uart_port)
serial8250_do_shutdown(uart_port); serial8250_do_shutdown(uart_port);
} }
static void __aspeed_vuart_set_throttle(struct uart_8250_port *up,
bool throttle)
{
unsigned char irqs = UART_IER_RLSI | UART_IER_RDI;
up->ier &= ~irqs;
if (!throttle)
up->ier |= irqs;
serial_out(up, UART_IER, up->ier);
}
static void aspeed_vuart_set_throttle(struct uart_port *port, bool throttle)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
__aspeed_vuart_set_throttle(up, throttle);
spin_unlock_irqrestore(&port->lock, flags);
}
static void aspeed_vuart_throttle(struct uart_port *port)
{
aspeed_vuart_set_throttle(port, true);
}
static void aspeed_vuart_unthrottle(struct uart_port *port)
{
aspeed_vuart_set_throttle(port, false);
}
static void aspeed_vuart_unthrottle_exp(struct timer_list *timer)
{
struct aspeed_vuart *vuart = from_timer(vuart, timer, unthrottle_timer);
struct uart_8250_port *up = vuart->port;
if (!tty_buffer_space_avail(&up->port.state->port)) {
mod_timer(&vuart->unthrottle_timer,
jiffies + unthrottle_timeout);
return;
}
aspeed_vuart_unthrottle(&up->port);
}
/*
* Custom interrupt handler to manage finer-grained flow control. Although we
* have throttle/unthrottle callbacks, we've seen that the VUART device can
* deliver characters faster than the ldisc has a chance to check buffer space
* against the throttle threshold. This results in dropped characters before
* the throttle.
*
* We do this by checking for flip buffer space before RX. If we have no space,
* throttle now and schedule an unthrottle for later, once the ldisc has had
* a chance to drain the buffers.
*/
static int aspeed_vuart_handle_irq(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int iir, lsr;
unsigned long flags;
int space, count;
iir = serial_port_in(port, UART_IIR);
if (iir & UART_IIR_NO_INT)
return 0;
spin_lock_irqsave(&port->lock, flags);
lsr = serial_port_in(port, UART_LSR);
if (lsr & (UART_LSR_DR | UART_LSR_BI)) {
space = tty_buffer_space_avail(&port->state->port);
if (!space) {
/* throttle and schedule an unthrottle later */
struct aspeed_vuart *vuart = port->private_data;
__aspeed_vuart_set_throttle(up, true);
if (!timer_pending(&vuart->unthrottle_timer)) {
vuart->port = up;
mod_timer(&vuart->unthrottle_timer,
jiffies + unthrottle_timeout);
}
} else {
count = min(space, 256);
do {
serial8250_read_char(up, lsr);
lsr = serial_in(up, UART_LSR);
if (--count == 0)
break;
} while (lsr & (UART_LSR_DR | UART_LSR_BI));
tty_flip_buffer_push(&port->state->port);
}
}
serial8250_modem_status(up);
if (lsr & UART_LSR_THRE)
serial8250_tx_chars(up);
spin_unlock_irqrestore(&port->lock, flags);
return 1;
}
static int aspeed_vuart_probe(struct platform_device *pdev) static int aspeed_vuart_probe(struct platform_device *pdev)
{ {
struct uart_8250_port port; struct uart_8250_port port;
@ -195,6 +314,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
vuart->dev = &pdev->dev; vuart->dev = &pdev->dev;
timer_setup(&vuart->unthrottle_timer, aspeed_vuart_unthrottle_exp, 0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
vuart->regs = devm_ioremap_resource(&pdev->dev, res); vuart->regs = devm_ioremap_resource(&pdev->dev, res);
@ -208,6 +328,9 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
port.port.mapsize = resource_size(res); port.port.mapsize = resource_size(res);
port.port.startup = aspeed_vuart_startup; port.port.startup = aspeed_vuart_startup;
port.port.shutdown = aspeed_vuart_shutdown; port.port.shutdown = aspeed_vuart_shutdown;
port.port.throttle = aspeed_vuart_throttle;
port.port.unthrottle = aspeed_vuart_unthrottle;
port.port.status = UPSTAT_SYNC_FIFO;
port.port.dev = &pdev->dev; port.port.dev = &pdev->dev;
rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
@ -253,6 +376,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
port.port.irq = irq_of_parse_and_map(np, 0); port.port.irq = irq_of_parse_and_map(np, 0);
port.port.irqflags = IRQF_SHARED; port.port.irqflags = IRQF_SHARED;
port.port.handle_irq = aspeed_vuart_handle_irq;
port.port.iotype = UPIO_MEM; port.port.iotype = UPIO_MEM;
port.port.type = PORT_16550A; port.port.type = PORT_16550A;
port.port.uartclk = clk; port.port.uartclk = clk;
@ -292,6 +416,7 @@ static int aspeed_vuart_remove(struct platform_device *pdev)
{ {
struct aspeed_vuart *vuart = platform_get_drvdata(pdev); struct aspeed_vuart *vuart = platform_get_drvdata(pdev);
del_timer_sync(&vuart->unthrottle_timer);
aspeed_vuart_set_enabled(vuart, false); aspeed_vuart_set_enabled(vuart, false);
serial8250_unregister_port(vuart->line); serial8250_unregister_port(vuart->line);
sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);

View File

@ -121,25 +121,44 @@ static void dw8250_check_lcr(struct uart_port *p, int value)
} }
/* Returns once the transmitter is empty or we run out of retries */ /* Returns once the transmitter is empty or we run out of retries */
static void dw8250_tx_wait_empty(struct uart_port *p, int tries) static void dw8250_tx_wait_empty(struct uart_port *p)
{ {
unsigned int tries = 20000;
unsigned int delay_threshold = tries - 1000;
unsigned int lsr; unsigned int lsr;
while (tries--) { while (tries--) {
lsr = readb (p->membase + (UART_LSR << p->regshift)); lsr = readb (p->membase + (UART_LSR << p->regshift));
if (lsr & UART_LSR_TEMT) if (lsr & UART_LSR_TEMT)
break; break;
udelay (10);
/* The device is first given a chance to empty without delay,
* to avoid slowdowns at high bitrates. If after 1000 tries
* the buffer has still not emptied, allow more time for low-
* speed links. */
if (tries < delay_threshold)
udelay (1);
} }
} }
static void dw8250_serial_out(struct uart_port *p, int offset, int value) static void dw8250_serial_out38x(struct uart_port *p, int offset, int value)
{ {
struct dw8250_data *d = p->private_data; struct dw8250_data *d = p->private_data;
/* Allow the TX to drain before we reconfigure */ /* Allow the TX to drain before we reconfigure */
if (offset == UART_LCR) if (offset == UART_LCR)
dw8250_tx_wait_empty(p, 1000); dw8250_tx_wait_empty(p);
writeb(value, p->membase + (offset << p->regshift));
if (offset == UART_LCR && !d->uart_16550_compatible)
dw8250_check_lcr(p, value);
}
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
writeb(value, p->membase + (offset << p->regshift)); writeb(value, p->membase + (offset << p->regshift));
@ -357,6 +376,9 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
p->serial_in = dw8250_serial_in32be; p->serial_in = dw8250_serial_in32be;
p->serial_out = dw8250_serial_out32be; p->serial_out = dw8250_serial_out32be;
} }
if (of_device_is_compatible(np, "marvell,armada-38x-uart"))
p->serial_out = dw8250_serial_out38x;
} else if (acpi_dev_present("APMC0D08", NULL, -1)) { } else if (acpi_dev_present("APMC0D08", NULL, -1)) {
p->iotype = UPIO_MEM32; p->iotype = UPIO_MEM32;
p->regshift = 2; p->regshift = 2;
@ -554,6 +576,10 @@ static int dw8250_probe(struct platform_device *pdev)
if (!data->skip_autocfg) if (!data->skip_autocfg)
dw8250_setup_port(p); dw8250_setup_port(p);
#ifdef CONFIG_PM
uart.capabilities |= UART_CAP_RPM;
#endif
/* If we have a valid fifosize, try hooking up DMA */ /* If we have a valid fifosize, try hooking up DMA */
if (p->fifosize) { if (p->fifosize) {
data->dma.rxconf.src_maxburst = p->fifosize / 4; data->dma.rxconf.src_maxburst = p->fifosize / 4;
@ -666,6 +692,7 @@ static const struct dev_pm_ops dw8250_pm_ops = {
static const struct of_device_id dw8250_of_match[] = { static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart" }, { .compatible = "snps,dw-apb-uart" },
{ .compatible = "cavium,octeon-3860-uart" }, { .compatible = "cavium,octeon-3860-uart" },
{ .compatible = "marvell,armada-38x-uart" },
{ /* Sentinel */ } { /* Sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, dw8250_of_match); MODULE_DEVICE_TABLE(of, dw8250_of_match);

View File

@ -122,7 +122,7 @@ static void __init init_port(struct earlycon_device *device)
serial8250_early_out(port, UART_FCR, 0); /* no fifo */ serial8250_early_out(port, UART_FCR, 0); /* no fifo */
serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */ serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */
if (port->uartclk && device->baud) { if (port->uartclk) {
divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud); divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud);
c = serial8250_early_in(port, UART_LCR); c = serial8250_early_in(port, UART_LCR);
serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB); serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB);

View File

@ -92,13 +92,43 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
goto err_unprepare; goto err_unprepare;
} }
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT |
UPF_FIXED_TYPE;
spin_lock_init(&port->lock); spin_lock_init(&port->lock);
port->mapbase = resource.start;
port->mapsize = resource_size(&resource);
/* Check for shifted address mapping */ if (resource_type(&resource) == IORESOURCE_IO) {
if (of_property_read_u32(np, "reg-offset", &prop) == 0) port->iotype = UPIO_PORT;
port->mapbase += prop; port->iobase = resource.start;
} else {
port->mapbase = resource.start;
port->mapsize = resource_size(&resource);
/* Check for shifted address mapping */
if (of_property_read_u32(np, "reg-offset", &prop) == 0)
port->mapbase += prop;
port->iotype = UPIO_MEM;
if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
switch (prop) {
case 1:
port->iotype = UPIO_MEM;
break;
case 2:
port->iotype = UPIO_MEM16;
break;
case 4:
port->iotype = of_device_is_big_endian(np) ?
UPIO_MEM32BE : UPIO_MEM32;
break;
default:
dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n",
prop);
ret = -EINVAL;
goto err_dispose;
}
}
port->flags |= UPF_IOREMAP;
}
/* Check for registers offset within the devices address range */ /* Check for registers offset within the devices address range */
if (of_property_read_u32(np, "reg-shift", &prop) == 0) if (of_property_read_u32(np, "reg-shift", &prop) == 0)
@ -114,26 +144,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->line = ret; port->line = ret;
port->irq = irq_of_parse_and_map(np, 0); port->irq = irq_of_parse_and_map(np, 0);
port->iotype = UPIO_MEM;
if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
switch (prop) {
case 1:
port->iotype = UPIO_MEM;
break;
case 2:
port->iotype = UPIO_MEM16;
break;
case 4:
port->iotype = of_device_is_big_endian(np) ?
UPIO_MEM32BE : UPIO_MEM32;
break;
default:
dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n",
prop);
ret = -EINVAL;
goto err_dispose;
}
}
info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL); info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
if (IS_ERR(info->rst)) { if (IS_ERR(info->rst)) {
@ -147,8 +157,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->type = type; port->type = type;
port->uartclk = clk; port->uartclk = clk;
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP port->irqflags |= IRQF_SHARED;
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
if (of_property_read_bool(np, "no-loopback-test")) if (of_property_read_bool(np, "no-loopback-test"))
port->flags |= UPF_SKIP_TEST; port->flags |= UPF_SKIP_TEST;

View File

@ -1110,13 +1110,14 @@ static int omap8250_no_handle_irq(struct uart_port *port)
return 0; return 0;
} }
static const u8 omap4_habit = UART_ERRATA_CLOCK_DISABLE;
static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE; static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE;
static const u8 dra742_habit = UART_ERRATA_CLOCK_DISABLE; static const u8 dra742_habit = UART_ERRATA_CLOCK_DISABLE;
static const struct of_device_id omap8250_dt_ids[] = { static const struct of_device_id omap8250_dt_ids[] = {
{ .compatible = "ti,omap2-uart" }, { .compatible = "ti,omap2-uart" },
{ .compatible = "ti,omap3-uart" }, { .compatible = "ti,omap3-uart" },
{ .compatible = "ti,omap4-uart" }, { .compatible = "ti,omap4-uart", .data = &omap4_habit, },
{ .compatible = "ti,am3352-uart", .data = &am3352_habit, }, { .compatible = "ti,am3352-uart", .data = &am3352_habit, },
{ .compatible = "ti,am4372-uart", .data = &am3352_habit, }, { .compatible = "ti,am4372-uart", .data = &am3352_habit, },
{ .compatible = "ti,dra742-uart", .data = &dra742_habit, }, { .compatible = "ti,dra742-uart", .data = &dra742_habit, },
@ -1310,8 +1311,17 @@ static void omap8250_complete(struct device *dev)
static int omap8250_suspend(struct device *dev) static int omap8250_suspend(struct device *dev)
{ {
struct omap8250_priv *priv = dev_get_drvdata(dev); struct omap8250_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(priv->line);
serial8250_suspend_port(priv->line); serial8250_suspend_port(priv->line);
pm_runtime_get_sync(dev);
if (!device_may_wakeup(dev))
priv->wer = 0;
serial_out(up, UART_OMAP_WER, priv->wer);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
flush_work(&priv->qos_work); flush_work(&priv->qos_work);
return 0; return 0;
} }
@ -1353,6 +1363,19 @@ static int omap8250_soft_reset(struct device *dev)
int sysc; int sysc;
int syss; int syss;
/*
* At least on omap4, unused uarts may not idle after reset without
* a basic scr dma configuration even with no dma in use. The
* module clkctrl status bits will be 1 instead of 3 blocking idle
* for the whole clockdomain. The softreset below will clear scr,
* and we restore it on resume so this is safe to do on all SoCs
* needing omap8250_soft_reset() quirk. Do it in two writes as
* recommended in the comment for omap8250_update_scr().
*/
serial_out(up, UART_OMAP_SCR, OMAP_UART_SCR_DMAMODE_1);
serial_out(up, UART_OMAP_SCR,
OMAP_UART_SCR_DMAMODE_1 | OMAP_UART_SCR_DMAMODE_CTL);
sysc = serial_in(up, UART_OMAP_SYSC); sysc = serial_in(up, UART_OMAP_SYSC);
/* softreset the UART */ /* softreset the UART */
@ -1403,6 +1426,8 @@ static int omap8250_runtime_suspend(struct device *dev)
/* Restore to UART mode after reset (for wakeup) */ /* Restore to UART mode after reset (for wakeup) */
omap8250_update_mdr1(up, priv); omap8250_update_mdr1(up, priv);
/* Restore wakeup enable register */
serial_out(up, UART_OMAP_WER, priv->wer);
} }
if (up->dma && up->dma->rxchan) if (up->dma && up->dma->rxchan)

View File

@ -243,6 +243,7 @@ static const struct serial8250_config uart_config[] = {
.fifo_size = 32, .fifo_size = 32,
.tx_loadsz = 32, .tx_loadsz = 32,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.rxtrig_bytes = {1, 8, 16, 30},
.flags = UART_CAP_FIFO | UART_CAP_AFE, .flags = UART_CAP_FIFO | UART_CAP_AFE,
}, },
[PORT_ALTR_16550_F64] = { [PORT_ALTR_16550_F64] = {
@ -250,6 +251,7 @@ static const struct serial8250_config uart_config[] = {
.fifo_size = 64, .fifo_size = 64,
.tx_loadsz = 64, .tx_loadsz = 64,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.rxtrig_bytes = {1, 16, 32, 62},
.flags = UART_CAP_FIFO | UART_CAP_AFE, .flags = UART_CAP_FIFO | UART_CAP_AFE,
}, },
[PORT_ALTR_16550_F128] = { [PORT_ALTR_16550_F128] = {
@ -257,6 +259,7 @@ static const struct serial8250_config uart_config[] = {
.fifo_size = 128, .fifo_size = 128,
.tx_loadsz = 128, .tx_loadsz = 128,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.rxtrig_bytes = {1, 32, 64, 126},
.flags = UART_CAP_FIFO | UART_CAP_AFE, .flags = UART_CAP_FIFO | UART_CAP_AFE,
}, },
/* /*
@ -1680,7 +1683,7 @@ static void serial8250_enable_ms(struct uart_port *port)
serial8250_rpm_put(up); serial8250_rpm_put(up);
} }
static void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
{ {
struct uart_port *port = &up->port; struct uart_port *port = &up->port;
unsigned char ch; unsigned char ch;
@ -1740,6 +1743,7 @@ static void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
} }
EXPORT_SYMBOL_GPL(serial8250_read_char);
/* /*
* serial8250_rx_chars: processes according to the passed in LSR * serial8250_rx_chars: processes according to the passed in LSR

View File

@ -115,7 +115,6 @@ config SERIAL_SB1250_DUART_CONSOLE
config SERIAL_ATMEL config SERIAL_ATMEL
bool "AT91 on-chip serial port support" bool "AT91 on-chip serial port support"
depends on HAS_DMA
depends on ARCH_AT91 || COMPILE_TEST depends on ARCH_AT91 || COMPILE_TEST
select SERIAL_CORE select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB select SERIAL_MCTRL_GPIO if GPIOLIB
@ -500,7 +499,6 @@ config SERIAL_SA1100_CONSOLE
config SERIAL_IMX config SERIAL_IMX
tristate "IMX serial port support" tristate "IMX serial port support"
depends on HAS_DMA
depends on ARCH_MXC || COMPILE_TEST depends on ARCH_MXC || COMPILE_TEST
select SERIAL_CORE select SERIAL_CORE
select RATIONAL select RATIONAL
@ -676,6 +674,8 @@ config SERIAL_SH_SCI
config SERIAL_SH_SCI_NR_UARTS config SERIAL_SH_SCI_NR_UARTS
int "Maximum number of SCI(F) serial ports" if EXPERT int "Maximum number of SCI(F) serial ports" if EXPERT
range 1 64 if 64BIT
range 1 32 if !64BIT
depends on SERIAL_SH_SCI depends on SERIAL_SH_SCI
default "3" if H8300 default "3" if H8300
default "10" if SUPERH default "10" if SUPERH
@ -1262,7 +1262,6 @@ config SERIAL_PCH_UART_CONSOLE
config SERIAL_MXS_AUART config SERIAL_MXS_AUART
tristate "MXS AUART support" tristate "MXS AUART support"
depends on HAS_DMA
depends on ARCH_MXS || MACH_ASM9260 || COMPILE_TEST depends on ARCH_MXS || MACH_ASM9260 || COMPILE_TEST
select SERIAL_CORE select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB select SERIAL_MCTRL_GPIO if GPIOLIB
@ -1295,7 +1294,7 @@ config SERIAL_XILINX_PS_UART_CONSOLE
config SERIAL_AR933X config SERIAL_AR933X
tristate "AR933X serial port support" tristate "AR933X serial port support"
depends on HAVE_CLK && SOC_AR933X depends on HAVE_CLK && ATH79
select SERIAL_CORE select SERIAL_CORE
help help
If you have an Atheros AR933X SOC based board and want to use the If you have an Atheros AR933X SOC based board and want to use the
@ -1473,7 +1472,6 @@ config SERIAL_SPRD_CONSOLE
config SERIAL_STM32 config SERIAL_STM32
tristate "STMicroelectronics STM32 serial port support" tristate "STMicroelectronics STM32 serial port support"
select SERIAL_CORE select SERIAL_CORE
depends on HAS_DMA
depends on ARCH_STM32 || COMPILE_TEST depends on ARCH_STM32 || COMPILE_TEST
help help
This driver is for the on-chip Serial Controller on This driver is for the on-chip Serial Controller on

View File

@ -1727,10 +1727,26 @@ static int pl011_allocate_irq(struct uart_amba_port *uap)
*/ */
static void pl011_enable_interrupts(struct uart_amba_port *uap) static void pl011_enable_interrupts(struct uart_amba_port *uap)
{ {
unsigned int i;
spin_lock_irq(&uap->port.lock); spin_lock_irq(&uap->port.lock);
/* Clear out any spuriously appearing RX interrupts */ /* Clear out any spuriously appearing RX interrupts */
pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR); pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
/*
* RXIS is asserted only when the RX FIFO transitions from below
* to above the trigger threshold. If the RX FIFO is already
* full to the threshold this can't happen and RXIS will now be
* stuck off. Drain the RX FIFO explicitly to fix this:
*/
for (i = 0; i < uap->fifosize * 2; ++i) {
if (pl011_read(uap, REG_FR) & UART01x_FR_RXFE)
break;
pl011_read(uap, REG_DR);
}
uap->im = UART011_RTIM; uap->im = UART011_RTIM;
if (!pl011_dma_rx_running(uap)) if (!pl011_dma_rx_running(uap))
uap->im |= UART011_RXIM; uap->im |= UART011_RXIM;

View File

@ -1757,7 +1757,6 @@ static int atmel_startup(struct uart_port *port)
{ {
struct platform_device *pdev = to_platform_device(port->dev); struct platform_device *pdev = to_platform_device(port->dev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
struct tty_struct *tty = port->state->port.tty;
int retval; int retval;
/* /*
@ -1772,8 +1771,8 @@ static int atmel_startup(struct uart_port *port)
* Allocate the IRQ * Allocate the IRQ
*/ */
retval = request_irq(port->irq, atmel_interrupt, retval = request_irq(port->irq, atmel_interrupt,
IRQF_SHARED | IRQF_COND_SUSPEND, IRQF_SHARED | IRQF_COND_SUSPEND,
tty ? tty->name : "atmel_serial", port); dev_name(&pdev->dev), port);
if (retval) { if (retval) {
dev_err(port->dev, "atmel_startup - Can't get irq\n"); dev_err(port->dev, "atmel_startup - Can't get irq\n");
return retval; return retval;

View File

@ -246,7 +246,6 @@ int __init of_setup_earlycon(const struct earlycon_id *match,
return -ENXIO; return -ENXIO;
} }
port->mapbase = addr; port->mapbase = addr;
port->uartclk = BASE_BAUD * 16;
val = of_get_flat_dt_prop(node, "reg-offset", NULL); val = of_get_flat_dt_prop(node, "reg-offset", NULL);
if (val) if (val)
@ -281,6 +280,10 @@ int __init of_setup_earlycon(const struct earlycon_id *match,
if (val) if (val)
early_console_dev.baud = be32_to_cpu(*val); early_console_dev.baud = be32_to_cpu(*val);
val = of_get_flat_dt_prop(node, "clock-frequency", NULL);
if (val)
port->uartclk = be32_to_cpu(*val);
if (options) { if (options) {
early_console_dev.baud = simple_strtoul(options, NULL, 0); early_console_dev.baud = simple_strtoul(options, NULL, 0);
strlcpy(early_console_dev.options, options, strlcpy(early_console_dev.options, options,

View File

@ -1291,18 +1291,13 @@ static void imx_uart_enable_dma(struct imx_port *sport)
static void imx_uart_disable_dma(struct imx_port *sport) static void imx_uart_disable_dma(struct imx_port *sport)
{ {
u32 ucr1, ucr2; u32 ucr1;
/* clear UCR1 */ /* clear UCR1 */
ucr1 = imx_uart_readl(sport, UCR1); ucr1 = imx_uart_readl(sport, UCR1);
ucr1 &= ~(UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN); ucr1 &= ~(UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN);
imx_uart_writel(sport, ucr1, UCR1); imx_uart_writel(sport, ucr1, UCR1);
/* clear UCR2 */
ucr2 = imx_uart_readl(sport, UCR2);
ucr2 &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN);
imx_uart_writel(sport, ucr2, UCR2);
imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
sport->dma_is_enabled = 0; sport->dma_is_enabled = 0;
@ -1427,13 +1422,21 @@ static void imx_uart_shutdown(struct uart_port *port)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = (struct imx_port *)port;
unsigned long flags; unsigned long flags;
u32 ucr1, ucr2; u32 ucr1, ucr2, ucr4;
if (sport->dma_is_enabled) { if (sport->dma_is_enabled) {
sport->dma_is_rxing = 0;
sport->dma_is_txing = 0;
dmaengine_terminate_sync(sport->dma_chan_tx); dmaengine_terminate_sync(sport->dma_chan_tx);
if (sport->dma_is_txing) {
dma_unmap_sg(sport->port.dev, &sport->tx_sgl[0],
sport->dma_tx_nents, DMA_TO_DEVICE);
sport->dma_is_txing = 0;
}
dmaengine_terminate_sync(sport->dma_chan_rx); dmaengine_terminate_sync(sport->dma_chan_rx);
if (sport->dma_is_rxing) {
dma_unmap_sg(sport->port.dev, &sport->rx_sgl,
1, DMA_FROM_DEVICE);
sport->dma_is_rxing = 0;
}
spin_lock_irqsave(&sport->port.lock, flags); spin_lock_irqsave(&sport->port.lock, flags);
imx_uart_stop_tx(port); imx_uart_stop_tx(port);
@ -1449,6 +1452,10 @@ static void imx_uart_shutdown(struct uart_port *port)
ucr2 = imx_uart_readl(sport, UCR2); ucr2 = imx_uart_readl(sport, UCR2);
ucr2 &= ~(UCR2_TXEN | UCR2_ATEN); ucr2 &= ~(UCR2_TXEN | UCR2_ATEN);
imx_uart_writel(sport, ucr2, UCR2); imx_uart_writel(sport, ucr2, UCR2);
ucr4 = imx_uart_readl(sport, UCR4);
ucr4 &= ~UCR4_OREN;
imx_uart_writel(sport, ucr4, UCR4);
spin_unlock_irqrestore(&sport->port.lock, flags); spin_unlock_irqrestore(&sport->port.lock, flags);
/* /*
@ -2425,8 +2432,7 @@ static void imx_uart_enable_wakeup(struct imx_port *sport, bool on)
static int imx_uart_suspend_noirq(struct device *dev) static int imx_uart_suspend_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = dev_get_drvdata(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
imx_uart_save_context(sport); imx_uart_save_context(sport);
@ -2437,8 +2443,7 @@ static int imx_uart_suspend_noirq(struct device *dev)
static int imx_uart_resume_noirq(struct device *dev) static int imx_uart_resume_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = dev_get_drvdata(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
int ret; int ret;
ret = clk_enable(sport->clk_ipg); ret = clk_enable(sport->clk_ipg);
@ -2452,8 +2457,7 @@ static int imx_uart_resume_noirq(struct device *dev)
static int imx_uart_suspend(struct device *dev) static int imx_uart_suspend(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = dev_get_drvdata(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
int ret; int ret;
uart_suspend_port(&imx_uart_uart_driver, &sport->port); uart_suspend_port(&imx_uart_uart_driver, &sport->port);
@ -2471,8 +2475,7 @@ static int imx_uart_suspend(struct device *dev)
static int imx_uart_resume(struct device *dev) static int imx_uart_resume(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = dev_get_drvdata(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
/* disable wakeup from i.MX UART */ /* disable wakeup from i.MX UART */
imx_uart_enable_wakeup(sport, false); imx_uart_enable_wakeup(sport, false);
@ -2487,8 +2490,7 @@ static int imx_uart_resume(struct device *dev)
static int imx_uart_freeze(struct device *dev) static int imx_uart_freeze(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = dev_get_drvdata(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
uart_suspend_port(&imx_uart_uart_driver, &sport->port); uart_suspend_port(&imx_uart_uart_driver, &sport->port);
@ -2497,8 +2499,7 @@ static int imx_uart_freeze(struct device *dev)
static int imx_uart_thaw(struct device *dev) static int imx_uart_thaw(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = dev_get_drvdata(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
uart_resume_port(&imx_uart_uart_driver, &sport->port); uart_resume_port(&imx_uart_uart_driver, &sport->port);

View File

@ -1812,11 +1812,34 @@ static const struct of_device_id msm_match_table[] = {
}; };
MODULE_DEVICE_TABLE(of, msm_match_table); MODULE_DEVICE_TABLE(of, msm_match_table);
static int __maybe_unused msm_serial_suspend(struct device *dev)
{
struct msm_port *port = dev_get_drvdata(dev);
uart_suspend_port(&msm_uart_driver, &port->uart);
return 0;
}
static int __maybe_unused msm_serial_resume(struct device *dev)
{
struct msm_port *port = dev_get_drvdata(dev);
uart_resume_port(&msm_uart_driver, &port->uart);
return 0;
}
static const struct dev_pm_ops msm_serial_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(msm_serial_suspend, msm_serial_resume)
};
static struct platform_driver msm_platform_driver = { static struct platform_driver msm_platform_driver = {
.remove = msm_serial_remove, .remove = msm_serial_remove,
.probe = msm_serial_probe, .probe = msm_serial_probe,
.driver = { .driver = {
.name = "msm_serial", .name = "msm_serial",
.pm = &msm_serial_dev_pm_ops,
.of_match_table = msm_match_table, .of_match_table = msm_match_table,
}, },
}; };

View File

@ -71,6 +71,8 @@
#define UART_BRDV 0x10 #define UART_BRDV 0x10
#define BRDV_BAUD_MASK 0x3FF #define BRDV_BAUD_MASK 0x3FF
#define UART_OSAMP 0x14
#define MVEBU_NR_UARTS 2 #define MVEBU_NR_UARTS 2
#define MVEBU_UART_TYPE "mvebu-uart" #define MVEBU_UART_TYPE "mvebu-uart"
@ -108,6 +110,17 @@ struct mvebu_uart_driver_data {
struct uart_flags flags; struct uart_flags flags;
}; };
/* Saved registers during suspend */
struct mvebu_uart_pm_regs {
unsigned int rbr;
unsigned int tsh;
unsigned int ctrl;
unsigned int intr;
unsigned int stat;
unsigned int brdv;
unsigned int osamp;
};
/* MVEBU UART driver structure */ /* MVEBU UART driver structure */
struct mvebu_uart { struct mvebu_uart {
struct uart_port *port; struct uart_port *port;
@ -115,6 +128,9 @@ struct mvebu_uart {
int irq[UART_IRQ_COUNT]; int irq[UART_IRQ_COUNT];
unsigned char __iomem *nb; unsigned char __iomem *nb;
struct mvebu_uart_driver_data *data; struct mvebu_uart_driver_data *data;
#if defined(CONFIG_PM)
struct mvebu_uart_pm_regs pm_regs;
#endif /* CONFIG_PM */
}; };
static struct mvebu_uart *to_mvuart(struct uart_port *port) static struct mvebu_uart *to_mvuart(struct uart_port *port)
@ -718,6 +734,51 @@ static struct uart_driver mvebu_uart_driver = {
#endif #endif
}; };
#if defined(CONFIG_PM)
static int mvebu_uart_suspend(struct device *dev)
{
struct mvebu_uart *mvuart = dev_get_drvdata(dev);
struct uart_port *port = mvuart->port;
uart_suspend_port(&mvebu_uart_driver, port);
mvuart->pm_regs.rbr = readl(port->membase + UART_RBR(port));
mvuart->pm_regs.tsh = readl(port->membase + UART_TSH(port));
mvuart->pm_regs.ctrl = readl(port->membase + UART_CTRL(port));
mvuart->pm_regs.intr = readl(port->membase + UART_INTR(port));
mvuart->pm_regs.stat = readl(port->membase + UART_STAT);
mvuart->pm_regs.brdv = readl(port->membase + UART_BRDV);
mvuart->pm_regs.osamp = readl(port->membase + UART_OSAMP);
device_set_wakeup_enable(dev, true);
return 0;
}
static int mvebu_uart_resume(struct device *dev)
{
struct mvebu_uart *mvuart = dev_get_drvdata(dev);
struct uart_port *port = mvuart->port;
writel(mvuart->pm_regs.rbr, port->membase + UART_RBR(port));
writel(mvuart->pm_regs.tsh, port->membase + UART_TSH(port));
writel(mvuart->pm_regs.ctrl, port->membase + UART_CTRL(port));
writel(mvuart->pm_regs.intr, port->membase + UART_INTR(port));
writel(mvuart->pm_regs.stat, port->membase + UART_STAT);
writel(mvuart->pm_regs.brdv, port->membase + UART_BRDV);
writel(mvuart->pm_regs.osamp, port->membase + UART_OSAMP);
uart_resume_port(&mvebu_uart_driver, port);
return 0;
}
static const struct dev_pm_ops mvebu_uart_pm_ops = {
.suspend = mvebu_uart_suspend,
.resume = mvebu_uart_resume,
};
#endif /* CONFIG_PM */
static const struct of_device_id mvebu_uart_of_match[]; static const struct of_device_id mvebu_uart_of_match[];
/* Counter to keep track of each UART port id when not using CONFIG_OF */ /* Counter to keep track of each UART port id when not using CONFIG_OF */
@ -891,6 +952,9 @@ static struct platform_driver mvebu_uart_platform_driver = {
.name = "mvebu-uart", .name = "mvebu-uart",
.of_match_table = of_match_ptr(mvebu_uart_of_match), .of_match_table = of_match_ptr(mvebu_uart_of_match),
.suppress_bind_attrs = true, .suppress_bind_attrs = true,
#if defined(CONFIG_PM)
.pm = &mvebu_uart_pm_ops,
#endif /* CONFIG_PM */
}, },
}; };

View File

@ -98,14 +98,13 @@ struct qcom_geni_serial_port {
enum geni_se_xfer_mode xfer_mode; enum geni_se_xfer_mode xfer_mode;
bool setup; bool setup;
int (*handle_rx)(struct uart_port *uport, u32 bytes, bool drop); int (*handle_rx)(struct uart_port *uport, u32 bytes, bool drop);
unsigned int xmit_size;
unsigned int baud; unsigned int baud;
unsigned int tx_bytes_pw; unsigned int tx_bytes_pw;
unsigned int rx_bytes_pw; unsigned int rx_bytes_pw;
bool brk; bool brk;
}; };
static const struct uart_ops qcom_geni_serial_pops; static const struct uart_ops qcom_geni_console_pops;
static struct uart_driver qcom_geni_console_driver; static struct uart_driver qcom_geni_console_driver;
static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop); static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop);
static unsigned int qcom_geni_serial_tx_empty(struct uart_port *port); static unsigned int qcom_geni_serial_tx_empty(struct uart_port *port);
@ -118,7 +117,14 @@ static const unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
#define to_dev_port(ptr, member) \ #define to_dev_port(ptr, member) \
container_of(ptr, struct qcom_geni_serial_port, member) container_of(ptr, struct qcom_geni_serial_port, member)
static struct qcom_geni_serial_port qcom_geni_console_port; static struct qcom_geni_serial_port qcom_geni_console_port = {
.uport = {
.iotype = UPIO_MEM,
.ops = &qcom_geni_console_pops,
.flags = UPF_BOOT_AUTOCONF,
.line = 0,
},
};
static int qcom_geni_serial_request_port(struct uart_port *uport) static int qcom_geni_serial_request_port(struct uart_port *uport)
{ {
@ -189,8 +195,19 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500; timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500;
} }
return !readl_poll_timeout_atomic(uport->membase + offset, reg, /*
(bool)(reg & field) == set, 10, timeout_us); * Use custom implementation instead of readl_poll_atomic since ktimer
* is not ready at the time of early console.
*/
timeout_us = DIV_ROUND_UP(timeout_us, 10) * 10;
while (timeout_us) {
reg = readl_relaxed(uport->membase + offset);
if ((bool)(reg & field) == set)
return true;
udelay(10);
timeout_us -= 10;
}
return false;
} }
static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size) static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size)
@ -286,6 +303,10 @@ __qcom_geni_serial_console_write(struct uart_port *uport, const char *s,
u32 bytes_to_send = count; u32 bytes_to_send = count;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
/*
* uart_console_write() adds a carriage return for each newline.
* Account for additional bytes to be written.
*/
if (s[i] == '\n') if (s[i] == '\n')
bytes_to_send++; bytes_to_send++;
} }
@ -305,7 +326,7 @@ __qcom_geni_serial_console_write(struct uart_port *uport, const char *s,
if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
M_TX_FIFO_WATERMARK_EN, true)) M_TX_FIFO_WATERMARK_EN, true))
break; break;
chars_to_write = min_t(size_t, (size_t)(count - i), avail / 2); chars_to_write = min_t(size_t, count - i, avail / 2);
uart_console_write(uport, s + i, chars_to_write, uart_console_write(uport, s + i, chars_to_write,
qcom_geni_serial_wr_char); qcom_geni_serial_wr_char);
writel_relaxed(M_TX_FIFO_WATERMARK_EN, uport->membase + writel_relaxed(M_TX_FIFO_WATERMARK_EN, uport->membase +
@ -406,20 +427,18 @@ static void qcom_geni_serial_start_tx(struct uart_port *uport)
u32 status; u32 status;
if (port->xfer_mode == GENI_SE_FIFO) { if (port->xfer_mode == GENI_SE_FIFO) {
status = readl_relaxed(uport->membase + SE_GENI_STATUS); /*
* readl ensures reading & writing of IRQ_EN register
* is not re-ordered before checking the status of the
* Serial Engine.
*/
status = readl(uport->membase + SE_GENI_STATUS);
if (status & M_GENI_CMD_ACTIVE) if (status & M_GENI_CMD_ACTIVE)
return; return;
if (!qcom_geni_serial_tx_empty(uport)) if (!qcom_geni_serial_tx_empty(uport))
return; return;
/*
* Ensure writing to IRQ_EN & watermark registers are not
* re-ordered before checking the status of the Serial
* Engine and TX FIFO
*/
mb();
irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN; irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN;
@ -442,7 +461,6 @@ static void qcom_geni_serial_stop_tx(struct uart_port *uport)
writel_relaxed(0, uport->membase + writel_relaxed(0, uport->membase +
SE_GENI_TX_WATERMARK_REG); SE_GENI_TX_WATERMARK_REG);
} }
port->xmit_size = 0;
writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
status = readl_relaxed(uport->membase + SE_GENI_STATUS); status = readl_relaxed(uport->membase + SE_GENI_STATUS);
/* Possible stop tx is called multiple times. */ /* Possible stop tx is called multiple times. */
@ -572,21 +590,14 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport)
chunk = uart_circ_chars_pending(xmit); chunk = uart_circ_chars_pending(xmit);
status = readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS); status = readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS);
/* Both FIFO and framework buffer are drained */ /* Both FIFO and framework buffer are drained */
if (chunk == port->xmit_size && !status) { if (!chunk && !status) {
port->xmit_size = 0;
uart_circ_clear(xmit);
qcom_geni_serial_stop_tx(uport); qcom_geni_serial_stop_tx(uport);
goto out_write_wakeup; goto out_write_wakeup;
} }
chunk -= port->xmit_size;
avail = (port->tx_fifo_depth - port->tx_wm) * port->tx_bytes_pw; avail = (port->tx_fifo_depth - port->tx_wm) * port->tx_bytes_pw;
tail = (xmit->tail + port->xmit_size) & (UART_XMIT_SIZE - 1); tail = xmit->tail;
if (chunk > (UART_XMIT_SIZE - tail)) chunk = min3((size_t)chunk, (size_t)(UART_XMIT_SIZE - tail), avail);
chunk = UART_XMIT_SIZE - tail;
if (chunk > avail)
chunk = avail;
if (!chunk) if (!chunk)
goto out_write_wakeup; goto out_write_wakeup;
@ -595,24 +606,27 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport)
remaining = chunk; remaining = chunk;
for (i = 0; i < chunk; ) { for (i = 0; i < chunk; ) {
unsigned int tx_bytes; unsigned int tx_bytes;
unsigned int buf = 0; u8 buf[sizeof(u32)];
int c; int c;
tx_bytes = min_t(size_t, remaining, (size_t)port->tx_bytes_pw); memset(buf, 0, ARRAY_SIZE(buf));
tx_bytes = min_t(size_t, remaining, port->tx_bytes_pw);
for (c = 0; c < tx_bytes ; c++) for (c = 0; c < tx_bytes ; c++)
buf |= (xmit->buf[tail + c] << (c * BITS_PER_BYTE)); buf[c] = xmit->buf[tail + c];
writel_relaxed(buf, uport->membase + SE_GENI_TX_FIFOn); iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1);
i += tx_bytes; i += tx_bytes;
tail = (tail + tx_bytes) & (UART_XMIT_SIZE - 1); tail += tx_bytes;
uport->icount.tx += tx_bytes; uport->icount.tx += tx_bytes;
remaining -= tx_bytes; remaining -= tx_bytes;
} }
xmit->tail = tail & (UART_XMIT_SIZE - 1);
qcom_geni_serial_poll_tx_done(uport); qcom_geni_serial_poll_tx_done(uport);
port->xmit_size += chunk;
out_write_wakeup: out_write_wakeup:
uart_write_wakeup(uport); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(uport);
} }
static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
@ -627,7 +641,7 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
struct qcom_geni_serial_port *port = to_dev_port(uport, uport); struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
if (uport->suspended) if (uport->suspended)
return IRQ_HANDLED; return IRQ_NONE;
spin_lock_irqsave(&uport->lock, flags); spin_lock_irqsave(&uport->lock, flags);
m_irq_status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS); m_irq_status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS);
@ -667,20 +681,16 @@ out_unlock:
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int get_tx_fifo_size(struct qcom_geni_serial_port *port) static void get_tx_fifo_size(struct qcom_geni_serial_port *port)
{ {
struct uart_port *uport; struct uart_port *uport;
if (!port)
return -ENODEV;
uport = &port->uport; uport = &port->uport;
port->tx_fifo_depth = geni_se_get_tx_fifo_depth(&port->se); port->tx_fifo_depth = geni_se_get_tx_fifo_depth(&port->se);
port->tx_fifo_width = geni_se_get_tx_fifo_width(&port->se); port->tx_fifo_width = geni_se_get_tx_fifo_width(&port->se);
port->rx_fifo_depth = geni_se_get_rx_fifo_depth(&port->se); port->rx_fifo_depth = geni_se_get_rx_fifo_depth(&port->se);
uport->fifosize = uport->fifosize =
(port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE; (port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE;
return 0;
} }
static void set_rfr_wm(struct qcom_geni_serial_port *port) static void set_rfr_wm(struct qcom_geni_serial_port *port)
@ -702,7 +712,6 @@ static void qcom_geni_serial_shutdown(struct uart_port *uport)
/* Stop the console before stopping the current tx */ /* Stop the console before stopping the current tx */
console_stop(uport->cons); console_stop(uport->cons);
disable_irq(uport->irq);
free_irq(uport->irq, uport); free_irq(uport->irq, uport);
spin_lock_irqsave(&uport->lock, flags); spin_lock_irqsave(&uport->lock, flags);
qcom_geni_serial_stop_tx(uport); qcom_geni_serial_stop_tx(uport);
@ -892,7 +901,7 @@ out_restart_rx:
static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport) static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport)
{ {
return !readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS); return !readl(uport->membase + SE_GENI_TX_FIFO_STATUS);
} }
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
@ -910,7 +919,7 @@ static int __init qcom_geni_console_setup(struct console *co, char *options)
port = get_port_from_line(co->index); port = get_port_from_line(co->index);
if (IS_ERR(port)) { if (IS_ERR(port)) {
pr_err("Invalid line %d(%d)\n", co->index, (int)PTR_ERR(port)); pr_err("Invalid line %d\n", co->index);
return PTR_ERR(port); return PTR_ERR(port);
} }
@ -942,6 +951,65 @@ static int __init qcom_geni_console_setup(struct console *co, char *options)
return uart_set_options(uport, co, baud, parity, bits, flow); return uart_set_options(uport, co, baud, parity, bits, flow);
} }
static void qcom_geni_serial_earlycon_write(struct console *con,
const char *s, unsigned int n)
{
struct earlycon_device *dev = con->data;
__qcom_geni_serial_console_write(&dev->port, s, n);
}
static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev,
const char *opt)
{
struct uart_port *uport = &dev->port;
u32 tx_trans_cfg;
u32 tx_parity_cfg = 0; /* Disable Tx Parity */
u32 rx_trans_cfg = 0;
u32 rx_parity_cfg = 0; /* Disable Rx Parity */
u32 stop_bit_len = 0; /* Default stop bit length - 1 bit */
u32 bits_per_char;
struct geni_se se;
if (!uport->membase)
return -EINVAL;
memset(&se, 0, sizeof(se));
se.base = uport->membase;
if (geni_se_read_proto(&se) != GENI_SE_UART)
return -ENXIO;
/*
* Ignore Flow control.
* n = 8.
*/
tx_trans_cfg = UART_CTS_MASK;
bits_per_char = BITS_PER_BYTE;
/*
* Make an unconditional cancel on the main sequencer to reset
* it else we could end up in data loss scenarios.
*/
qcom_geni_serial_poll_tx_done(uport);
qcom_geni_serial_abort_rx(uport);
geni_se_config_packing(&se, BITS_PER_BYTE, 1, false, true, false);
geni_se_init(&se, DEF_FIFO_DEPTH_WORDS / 2, DEF_FIFO_DEPTH_WORDS - 2);
geni_se_select_mode(&se, GENI_SE_FIFO);
writel_relaxed(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG);
writel_relaxed(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG);
writel_relaxed(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG);
writel_relaxed(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG);
writel_relaxed(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN);
writel_relaxed(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN);
writel_relaxed(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN);
dev->con->write = qcom_geni_serial_earlycon_write;
dev->con->setup = NULL;
return 0;
}
OF_EARLYCON_DECLARE(qcom_geni, "qcom,geni-debug-uart",
qcom_geni_serial_earlycon_setup);
static int __init console_register(struct uart_driver *drv) static int __init console_register(struct uart_driver *drv)
{ {
return uart_register_driver(drv); return uart_register_driver(drv);
@ -1026,16 +1094,13 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
if (pdev->dev.of_node) if (pdev->dev.of_node)
line = of_alias_get_id(pdev->dev.of_node, "serial"); line = of_alias_get_id(pdev->dev.of_node, "serial");
else
line = pdev->id;
if (line < 0 || line >= GENI_UART_CONS_PORTS) if (line < 0 || line >= GENI_UART_CONS_PORTS)
return -ENXIO; return -ENXIO;
port = get_port_from_line(line); port = get_port_from_line(line);
if (IS_ERR(port)) { if (IS_ERR(port)) {
ret = PTR_ERR(port); dev_err(&pdev->dev, "Invalid line %d\n", line);
dev_err(&pdev->dev, "Invalid line %d(%d)\n", line, ret); return PTR_ERR(port);
return ret;
} }
uport = &port->uport; uport = &port->uport;
@ -1072,7 +1137,6 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
uport->private_data = &qcom_geni_console_driver; uport->private_data = &qcom_geni_console_driver;
platform_set_drvdata(pdev, port); platform_set_drvdata(pdev, port);
port->handle_rx = handle_rx_console; port->handle_rx = handle_rx_console;
port->setup = false;
return uart_add_one_port(&qcom_geni_console_driver, uport); return uart_add_one_port(&qcom_geni_console_driver, uport);
} }
@ -1087,8 +1151,7 @@ static int qcom_geni_serial_remove(struct platform_device *pdev)
static int __maybe_unused qcom_geni_serial_sys_suspend_noirq(struct device *dev) static int __maybe_unused qcom_geni_serial_sys_suspend_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
struct uart_port *uport = &port->uport; struct uart_port *uport = &port->uport;
uart_suspend_port(uport->private_data, uport); uart_suspend_port(uport->private_data, uport);
@ -1097,12 +1160,19 @@ static int __maybe_unused qcom_geni_serial_sys_suspend_noirq(struct device *dev)
static int __maybe_unused qcom_geni_serial_sys_resume_noirq(struct device *dev) static int __maybe_unused qcom_geni_serial_sys_resume_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
struct uart_port *uport = &port->uport; struct uart_port *uport = &port->uport;
if (console_suspend_enabled && uport->suspended) { if (console_suspend_enabled && uport->suspended) {
uart_resume_port(uport->private_data, uport); uart_resume_port(uport->private_data, uport);
/*
* uart_suspend_port() invokes port shutdown which in turn
* frees the irq. uart_resume_port invokes port startup which
* performs request_irq. The request_irq auto-enables the IRQ.
* In addition, resume_noirq implicitly enables the IRQ and
* leads to an unbalanced IRQ enable warning. Disable the IRQ
* before returning so that the warning is suppressed.
*/
disable_irq(uport->irq); disable_irq(uport->irq);
} }
return 0; return 0;
@ -1133,11 +1203,6 @@ static int __init qcom_geni_serial_init(void)
{ {
int ret; int ret;
qcom_geni_console_port.uport.iotype = UPIO_MEM;
qcom_geni_console_port.uport.ops = &qcom_geni_console_pops;
qcom_geni_console_port.uport.flags = UPF_BOOT_AUTOCONF;
qcom_geni_console_port.uport.line = 0;
ret = console_register(&qcom_geni_console_driver); ret = console_register(&qcom_geni_console_driver);
if (ret) if (ret)
return ret; return ret;

View File

@ -856,35 +856,54 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p) static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
{ {
struct s3c24xx_uart_dma *dma = p->dma; struct s3c24xx_uart_dma *dma = p->dma;
struct dma_slave_caps dma_caps;
const char *reason = NULL;
int ret; int ret;
/* Default slave configuration parameters */ /* Default slave configuration parameters */
dma->rx_conf.direction = DMA_DEV_TO_MEM; dma->rx_conf.direction = DMA_DEV_TO_MEM;
dma->rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma->rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma->rx_conf.src_addr = p->port.mapbase + S3C2410_URXH; dma->rx_conf.src_addr = p->port.mapbase + S3C2410_URXH;
dma->rx_conf.src_maxburst = 16; dma->rx_conf.src_maxburst = 1;
dma->tx_conf.direction = DMA_MEM_TO_DEV; dma->tx_conf.direction = DMA_MEM_TO_DEV;
dma->tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma->tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma->tx_conf.dst_addr = p->port.mapbase + S3C2410_UTXH; dma->tx_conf.dst_addr = p->port.mapbase + S3C2410_UTXH;
if (dma_get_cache_alignment() >= 16) dma->tx_conf.dst_maxburst = 1;
dma->tx_conf.dst_maxburst = 16;
else
dma->tx_conf.dst_maxburst = 1;
dma->rx_chan = dma_request_chan(p->port.dev, "rx"); dma->rx_chan = dma_request_chan(p->port.dev, "rx");
if (IS_ERR(dma->rx_chan)) if (IS_ERR(dma->rx_chan)) {
return PTR_ERR(dma->rx_chan); reason = "DMA RX channel request failed";
ret = PTR_ERR(dma->rx_chan);
goto err_warn;
}
ret = dma_get_slave_caps(dma->rx_chan, &dma_caps);
if (ret < 0 ||
dma_caps.residue_granularity < DMA_RESIDUE_GRANULARITY_BURST) {
reason = "insufficient DMA RX engine capabilities";
ret = -EOPNOTSUPP;
goto err_release_rx;
}
dmaengine_slave_config(dma->rx_chan, &dma->rx_conf); dmaengine_slave_config(dma->rx_chan, &dma->rx_conf);
dma->tx_chan = dma_request_chan(p->port.dev, "tx"); dma->tx_chan = dma_request_chan(p->port.dev, "tx");
if (IS_ERR(dma->tx_chan)) { if (IS_ERR(dma->tx_chan)) {
reason = "DMA TX channel request failed";
ret = PTR_ERR(dma->tx_chan); ret = PTR_ERR(dma->tx_chan);
goto err_release_rx; goto err_release_rx;
} }
ret = dma_get_slave_caps(dma->tx_chan, &dma_caps);
if (ret < 0 ||
dma_caps.residue_granularity < DMA_RESIDUE_GRANULARITY_BURST) {
reason = "insufficient DMA TX engine capabilities";
ret = -EOPNOTSUPP;
goto err_release_tx;
}
dmaengine_slave_config(dma->tx_chan, &dma->tx_conf); dmaengine_slave_config(dma->tx_chan, &dma->tx_conf);
/* RX buffer */ /* RX buffer */
@ -899,6 +918,7 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
dma->rx_addr = dma_map_single(p->port.dev, dma->rx_buf, dma->rx_addr = dma_map_single(p->port.dev, dma->rx_buf,
dma->rx_size, DMA_FROM_DEVICE); dma->rx_size, DMA_FROM_DEVICE);
if (dma_mapping_error(p->port.dev, dma->rx_addr)) { if (dma_mapping_error(p->port.dev, dma->rx_addr)) {
reason = "DMA mapping error for RX buffer";
ret = -EIO; ret = -EIO;
goto err_free_rx; goto err_free_rx;
} }
@ -907,6 +927,7 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
dma->tx_addr = dma_map_single(p->port.dev, p->port.state->xmit.buf, dma->tx_addr = dma_map_single(p->port.dev, p->port.state->xmit.buf,
UART_XMIT_SIZE, DMA_TO_DEVICE); UART_XMIT_SIZE, DMA_TO_DEVICE);
if (dma_mapping_error(p->port.dev, dma->tx_addr)) { if (dma_mapping_error(p->port.dev, dma->tx_addr)) {
reason = "DMA mapping error for TX buffer";
ret = -EIO; ret = -EIO;
goto err_unmap_rx; goto err_unmap_rx;
} }
@ -922,6 +943,9 @@ err_release_tx:
dma_release_channel(dma->tx_chan); dma_release_channel(dma->tx_chan);
err_release_rx: err_release_rx:
dma_release_channel(dma->rx_chan); dma_release_channel(dma->rx_chan);
err_warn:
if (reason)
dev_warn(p->port.dev, "%s, DMA will not be used\n", reason);
return ret; return ret;
} }
@ -1040,8 +1064,6 @@ static int s3c64xx_serial_startup(struct uart_port *port)
if (ourport->dma) { if (ourport->dma) {
ret = s3c24xx_serial_request_dma(ourport); ret = s3c24xx_serial_request_dma(ourport);
if (ret < 0) { if (ret < 0) {
dev_warn(port->dev,
"DMA request failed, DMA will not be used\n");
devm_kfree(port->dev, ourport->dma); devm_kfree(port->dev, ourport->dma);
ourport->dma = NULL; ourport->dma = NULL;
} }

View File

@ -1168,7 +1168,10 @@ static int sc16is7xx_probe(struct device *dev,
else else
return PTR_ERR(s->clk); return PTR_ERR(s->clk);
} else { } else {
clk_prepare_enable(s->clk); ret = clk_prepare_enable(s->clk);
if (ret)
return ret;
freq = clk_get_rate(s->clk); freq = clk_get_rate(s->clk);
} }

View File

@ -674,8 +674,8 @@ static void uart_send_xchar(struct tty_struct *tty, char ch)
static void uart_throttle(struct tty_struct *tty) static void uart_throttle(struct tty_struct *tty)
{ {
struct uart_state *state = tty->driver_data; struct uart_state *state = tty->driver_data;
upstat_t mask = UPSTAT_SYNC_FIFO;
struct uart_port *port; struct uart_port *port;
upstat_t mask = 0;
port = uart_port_ref(state); port = uart_port_ref(state);
if (!port) if (!port)
@ -703,8 +703,8 @@ static void uart_throttle(struct tty_struct *tty)
static void uart_unthrottle(struct tty_struct *tty) static void uart_unthrottle(struct tty_struct *tty)
{ {
struct uart_state *state = tty->driver_data; struct uart_state *state = tty->driver_data;
upstat_t mask = UPSTAT_SYNC_FIFO;
struct uart_port *port; struct uart_port *port;
upstat_t mask = 0;
port = uart_port_ref(state); port = uart_port_ref(state);
if (!port) if (!port)

View File

@ -160,6 +160,7 @@ struct sci_port {
#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
static struct sci_port sci_ports[SCI_NPORTS]; static struct sci_port sci_ports[SCI_NPORTS];
static unsigned long sci_ports_in_use;
static struct uart_driver sci_uart_driver; static struct uart_driver sci_uart_driver;
static inline struct sci_port * static inline struct sci_port *
@ -2390,6 +2391,27 @@ done:
uart_update_timeout(port, termios->c_cflag, baud); uart_update_timeout(port, termios->c_cflag, baud);
/* byte size and parity */
switch (termios->c_cflag & CSIZE) {
case CS5:
bits = 7;
break;
case CS6:
bits = 8;
break;
case CS7:
bits = 9;
break;
default:
bits = 10;
break;
}
if (termios->c_cflag & CSTOPB)
bits++;
if (termios->c_cflag & PARENB)
bits++;
if (best_clk >= 0) { if (best_clk >= 0) {
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
switch (srr + 1) { switch (srr + 1) {
@ -2406,8 +2428,27 @@ done:
serial_port_out(port, SCSCR, scr_val | s->hscif_tot); serial_port_out(port, SCSCR, scr_val | s->hscif_tot);
serial_port_out(port, SCSMR, smr_val); serial_port_out(port, SCSMR, smr_val);
serial_port_out(port, SCBRR, brr); serial_port_out(port, SCBRR, brr);
if (sci_getreg(port, HSSRR)->size) if (sci_getreg(port, HSSRR)->size) {
serial_port_out(port, HSSRR, srr | HSCIF_SRE); unsigned int hssrr = srr | HSCIF_SRE;
/* Calculate deviation from intended rate at the
* center of the last stop bit in sampling clocks.
*/
int last_stop = bits * 2 - 1;
int deviation = min_err * srr * last_stop / 2 / baud;
if (abs(deviation) >= 2) {
/* At least two sampling clocks off at the
* last stop bit; we can increase the error
* margin by shifting the sampling point.
*/
int shift = min(-8, max(7, deviation / 2));
hssrr |= (shift << HSCIF_SRHP_SHIFT) &
HSCIF_SRHP_MASK;
hssrr |= HSCIF_SRDE;
}
serial_port_out(port, HSSRR, hssrr);
}
/* Wait one bit interval */ /* Wait one bit interval */
udelay((1000000 + (baud - 1)) / baud); udelay((1000000 + (baud - 1)) / baud);
@ -2474,27 +2515,6 @@ done:
* value obtained by this formula is too small. Therefore, if the value * value obtained by this formula is too small. Therefore, if the value
* is smaller than 20ms, use 20ms as the timeout value for DMA. * is smaller than 20ms, use 20ms as the timeout value for DMA.
*/ */
/* byte size and parity */
switch (termios->c_cflag & CSIZE) {
case CS5:
bits = 7;
break;
case CS6:
bits = 8;
break;
case CS7:
bits = 9;
break;
default:
bits = 10;
break;
}
if (termios->c_cflag & CSTOPB)
bits++;
if (termios->c_cflag & PARENB)
bits++;
s->rx_frame = (10000 * bits) / (baud / 100); s->rx_frame = (10000 * bits) / (baud / 100);
#ifdef CONFIG_SERIAL_SH_SCI_DMA #ifdef CONFIG_SERIAL_SH_SCI_DMA
s->rx_timeout = s->buf_len_rx * 2 * s->rx_frame; s->rx_timeout = s->buf_len_rx * 2 * s->rx_frame;
@ -2890,16 +2910,15 @@ static void serial_console_write(struct console *co, const char *s,
unsigned long flags; unsigned long flags;
int locked = 1; int locked = 1;
local_irq_save(flags);
#if defined(SUPPORT_SYSRQ) #if defined(SUPPORT_SYSRQ)
if (port->sysrq) if (port->sysrq)
locked = 0; locked = 0;
else else
#endif #endif
if (oops_in_progress) if (oops_in_progress)
locked = spin_trylock(&port->lock); locked = spin_trylock_irqsave(&port->lock, flags);
else else
spin_lock(&port->lock); spin_lock_irqsave(&port->lock, flags);
/* first save SCSCR then disable interrupts, keep clock source */ /* first save SCSCR then disable interrupts, keep clock source */
ctrl = serial_port_in(port, SCSCR); ctrl = serial_port_in(port, SCSCR);
@ -2919,8 +2938,7 @@ static void serial_console_write(struct console *co, const char *s,
serial_port_out(port, SCSCR, ctrl); serial_port_out(port, SCSCR, ctrl);
if (locked) if (locked)
spin_unlock(&port->lock); spin_unlock_irqrestore(&port->lock, flags);
local_irq_restore(flags);
} }
static int serial_console_setup(struct console *co, char *options) static int serial_console_setup(struct console *co, char *options)
@ -3026,6 +3044,7 @@ static int sci_remove(struct platform_device *dev)
{ {
struct sci_port *port = platform_get_drvdata(dev); struct sci_port *port = platform_get_drvdata(dev);
sci_ports_in_use &= ~BIT(port->port.line);
uart_remove_one_port(&sci_uart_driver, &port->port); uart_remove_one_port(&sci_uart_driver, &port->port);
sci_cleanup_single(port); sci_cleanup_single(port);
@ -3107,6 +3126,8 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
/* Get the line number from the aliases node. */ /* Get the line number from the aliases node. */
id = of_alias_get_id(np, "serial"); id = of_alias_get_id(np, "serial");
if (id < 0 && ~sci_ports_in_use)
id = ffz(sci_ports_in_use);
if (id < 0) { if (id < 0) {
dev_err(&pdev->dev, "failed to get alias id (%d)\n", id); dev_err(&pdev->dev, "failed to get alias id (%d)\n", id);
return NULL; return NULL;
@ -3141,6 +3162,9 @@ static int sci_probe_single(struct platform_device *dev,
dev_notice(&dev->dev, "Consider bumping CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); dev_notice(&dev->dev, "Consider bumping CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
return -EINVAL; return -EINVAL;
} }
BUILD_BUG_ON(SCI_NPORTS > sizeof(sci_ports_in_use) * 8);
if (sci_ports_in_use & BIT(index))
return -EBUSY;
mutex_lock(&sci_uart_registration_lock); mutex_lock(&sci_uart_registration_lock);
if (!sci_uart_driver.state) { if (!sci_uart_driver.state) {
@ -3239,6 +3263,7 @@ static int sci_probe(struct platform_device *dev)
sh_bios_gdb_detach(); sh_bios_gdb_detach();
#endif #endif
sci_ports_in_use |= BIT(dev_id);
return 0; return 0;
} }

View File

@ -130,6 +130,10 @@ enum {
/* HSSRR HSCIF */ /* HSSRR HSCIF */
#define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */ #define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */
#define HSCIF_SRDE BIT(14) /* Sampling Point Register Enable */
#define HSCIF_SRHP_SHIFT 8
#define HSCIF_SRHP_MASK 0x0f00
/* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */ /* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */
#define SCPCR_RTSC BIT(4) /* Serial Port RTS# Pin / Output Pin */ #define SCPCR_RTSC BIT(4) /* Serial Port RTS# Pin / Output Pin */

View File

@ -842,16 +842,14 @@ static int asc_serial_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int asc_serial_suspend(struct device *dev) static int asc_serial_suspend(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct uart_port *port = dev_get_drvdata(dev);
struct uart_port *port = platform_get_drvdata(pdev);
return uart_suspend_port(&asc_uart_driver, port); return uart_suspend_port(&asc_uart_driver, port);
} }
static int asc_serial_resume(struct device *dev) static int asc_serial_resume(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct uart_port *port = dev_get_drvdata(dev);
struct uart_port *port = platform_get_drvdata(pdev);
return uart_resume_port(&asc_uart_driver, port); return uart_resume_port(&asc_uart_driver, port);
} }

View File

@ -1097,45 +1097,6 @@ static const struct uart_ops cdns_uart_ops = {
#endif #endif
}; };
static struct uart_port cdns_uart_port[CDNS_UART_NR_PORTS];
/**
* cdns_uart_get_port - Configure the port from platform device resource info
* @id: Port id
*
* Return: a pointer to a uart_port or NULL for failure
*/
static struct uart_port *cdns_uart_get_port(int id)
{
struct uart_port *port;
/* Try the given port id if failed use default method */
if (id < CDNS_UART_NR_PORTS && cdns_uart_port[id].mapbase != 0) {
/* Find the next unused port */
for (id = 0; id < CDNS_UART_NR_PORTS; id++)
if (cdns_uart_port[id].mapbase == 0)
break;
}
if (id >= CDNS_UART_NR_PORTS)
return NULL;
port = &cdns_uart_port[id];
/* At this point, we've got an empty uart_port struct, initialize it */
spin_lock_init(&port->lock);
port->membase = NULL;
port->irq = 0;
port->type = PORT_UNKNOWN;
port->iotype = UPIO_MEM32;
port->flags = UPF_BOOT_AUTOCONF;
port->ops = &cdns_uart_ops;
port->fifosize = CDNS_UART_FIFO_SIZE;
port->line = id;
port->dev = NULL;
return port;
}
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/** /**
* cdns_uart_console_wait_tx - Wait for the TX to be full * cdns_uart_console_wait_tx - Wait for the TX to be full
@ -1206,6 +1167,10 @@ OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p8", cdns_early_console_setup);
OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p12", cdns_early_console_setup); OF_EARLYCON_DECLARE(cdns, "cdns,uart-r1p12", cdns_early_console_setup);
OF_EARLYCON_DECLARE(cdns, "xlnx,zynqmp-uart", cdns_early_console_setup); OF_EARLYCON_DECLARE(cdns, "xlnx,zynqmp-uart", cdns_early_console_setup);
/* Static pointer to console port */
static struct uart_port *console_port;
/** /**
* cdns_uart_console_write - perform write operation * cdns_uart_console_write - perform write operation
* @co: Console handle * @co: Console handle
@ -1215,7 +1180,7 @@ OF_EARLYCON_DECLARE(cdns, "xlnx,zynqmp-uart", cdns_early_console_setup);
static void cdns_uart_console_write(struct console *co, const char *s, static void cdns_uart_console_write(struct console *co, const char *s,
unsigned int count) unsigned int count)
{ {
struct uart_port *port = &cdns_uart_port[co->index]; struct uart_port *port = console_port;
unsigned long flags; unsigned long flags;
unsigned int imr, ctrl; unsigned int imr, ctrl;
int locked = 1; int locked = 1;
@ -1261,15 +1226,13 @@ static void cdns_uart_console_write(struct console *co, const char *s,
*/ */
static int __init cdns_uart_console_setup(struct console *co, char *options) static int __init cdns_uart_console_setup(struct console *co, char *options)
{ {
struct uart_port *port = &cdns_uart_port[co->index]; struct uart_port *port = console_port;
int baud = 9600; int baud = 9600;
int bits = 8; int bits = 8;
int parity = 'n'; int parity = 'n';
int flow = 'n'; int flow = 'n';
if (co->index < 0 || co->index >= CDNS_UART_NR_PORTS)
return -EINVAL;
if (!port->membase) { if (!port->membase) {
pr_debug("console on " CDNS_UART_TTY_NAME "%i not present\n", pr_debug("console on " CDNS_UART_TTY_NAME "%i not present\n",
co->index); co->index);
@ -1293,20 +1256,6 @@ static struct console cdns_uart_console = {
.index = -1, /* Specified on the cmdline (e.g. console=ttyPS ) */ .index = -1, /* Specified on the cmdline (e.g. console=ttyPS ) */
.data = &cdns_uart_uart_driver, .data = &cdns_uart_uart_driver,
}; };
/**
* cdns_uart_console_init - Initialization call
*
* Return: 0 on success, negative errno otherwise
*/
static int __init cdns_uart_console_init(void)
{
register_console(&cdns_uart_console);
return 0;
}
console_initcall(cdns_uart_console_init);
#endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */ #endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */
static struct uart_driver cdns_uart_uart_driver = { static struct uart_driver cdns_uart_uart_driver = {
@ -1430,8 +1379,7 @@ static int cdns_uart_resume(struct device *device)
#endif /* ! CONFIG_PM_SLEEP */ #endif /* ! CONFIG_PM_SLEEP */
static int __maybe_unused cdns_runtime_suspend(struct device *dev) static int __maybe_unused cdns_runtime_suspend(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct uart_port *port = dev_get_drvdata(dev);
struct uart_port *port = platform_get_drvdata(pdev);
struct cdns_uart *cdns_uart = port->private_data; struct cdns_uart *cdns_uart = port->private_data;
clk_disable(cdns_uart->uartclk); clk_disable(cdns_uart->uartclk);
@ -1441,8 +1389,7 @@ static int __maybe_unused cdns_runtime_suspend(struct device *dev)
static int __maybe_unused cdns_runtime_resume(struct device *dev) static int __maybe_unused cdns_runtime_resume(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct uart_port *port = dev_get_drvdata(dev);
struct uart_port *port = platform_get_drvdata(pdev);
struct cdns_uart *cdns_uart = port->private_data; struct cdns_uart *cdns_uart = port->private_data;
clk_enable(cdns_uart->pclk); clk_enable(cdns_uart->pclk);
@ -1487,6 +1434,9 @@ static int cdns_uart_probe(struct platform_device *pdev)
GFP_KERNEL); GFP_KERNEL);
if (!cdns_uart_data) if (!cdns_uart_data)
return -ENOMEM; return -ENOMEM;
port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
if (!port)
return -ENOMEM;
match = of_match_node(cdns_uart_of_match, pdev->dev.of_node); match = of_match_node(cdns_uart_of_match, pdev->dev.of_node);
if (match && match->data) { if (match && match->data) {
@ -1552,15 +1502,24 @@ static int cdns_uart_probe(struct platform_device *pdev)
if (id < 0) if (id < 0)
id = 0; id = 0;
/* Initialize the port structure */ if (id >= CDNS_UART_NR_PORTS) {
port = cdns_uart_get_port(id);
if (!port) {
dev_err(&pdev->dev, "Cannot get uart_port structure\n"); dev_err(&pdev->dev, "Cannot get uart_port structure\n");
rc = -ENODEV; rc = -ENODEV;
goto err_out_notif_unreg; goto err_out_notif_unreg;
} }
/* At this point, we've got an empty uart_port struct, initialize it */
spin_lock_init(&port->lock);
port->membase = NULL;
port->irq = 0;
port->type = PORT_UNKNOWN;
port->iotype = UPIO_MEM32;
port->flags = UPF_BOOT_AUTOCONF;
port->ops = &cdns_uart_ops;
port->fifosize = CDNS_UART_FIFO_SIZE;
port->line = id;
port->dev = NULL;
/* /*
* Register the port. * Register the port.
* This function also registers this device with the tty layer * This function also registers this device with the tty layer
@ -1579,6 +1538,17 @@ static int cdns_uart_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev); pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/*
* If console hasn't been found yet try to assign this port
* because it is required to be assigned for console setup function.
* If register_console() don't assign value, then console_port pointer
* is cleanup.
*/
if (cdns_uart_uart_driver.cons->index == -1)
console_port = port;
#endif
rc = uart_add_one_port(&cdns_uart_uart_driver, port); rc = uart_add_one_port(&cdns_uart_uart_driver, port);
if (rc) { if (rc) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
@ -1586,6 +1556,12 @@ static int cdns_uart_probe(struct platform_device *pdev)
goto err_out_pm_disable; goto err_out_pm_disable;
} }
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/* This is not port which is used for console that's why clean it up */
if (cdns_uart_uart_driver.cons->index == -1)
console_port = NULL;
#endif
return 0; return 0;
err_out_pm_disable: err_out_pm_disable:

View File

@ -1178,15 +1178,8 @@ static void csi_J(struct vc_data *vc, int vpar)
count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1; count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
start = (unsigned short *)vc->vc_origin; start = (unsigned short *)vc->vc_origin;
break; break;
case 3: /* erase scroll-back buffer (and whole display) */
scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,
vc->vc_screenbuf_size);
flush_scrollback(vc);
set_origin(vc);
if (con_is_visible(vc))
update_screen(vc);
/* fall through */
case 2: /* erase whole display */ case 2: /* erase whole display */
case 3: /* (and scrollback buffer later) */
count = vc->vc_cols * vc->vc_rows; count = vc->vc_cols * vc->vc_rows;
start = (unsigned short *)vc->vc_origin; start = (unsigned short *)vc->vc_origin;
break; break;
@ -1194,7 +1187,12 @@ static void csi_J(struct vc_data *vc, int vpar)
return; return;
} }
scr_memsetw(start, vc->vc_video_erase_char, 2 * count); scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
if (con_should_update(vc)) if (vpar == 3) {
set_origin(vc);
flush_scrollback(vc);
if (con_is_visible(vc))
update_screen(vc);
} else if (con_should_update(vc))
do_update_region(vc, (unsigned long) start, count); do_update_region(vc, (unsigned long) start, count);
vc->vc_need_wrap = 0; vc->vc_need_wrap = 0;
} }

View File

@ -163,6 +163,7 @@ extern void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl);
extern int fsl8250_handle_irq(struct uart_port *port); extern int fsl8250_handle_irq(struct uart_port *port);
int serial8250_handle_irq(struct uart_port *port, unsigned int iir); int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr); unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr);
void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr);
void serial8250_tx_chars(struct uart_8250_port *up); void serial8250_tx_chars(struct uart_8250_port *up);
unsigned int serial8250_modem_status(struct uart_8250_port *up); unsigned int serial8250_modem_status(struct uart_8250_port *up);
void serial8250_init_port(struct uart_8250_port *up); void serial8250_init_port(struct uart_8250_port *up);

View File

@ -233,6 +233,7 @@ struct uart_port {
#define UPSTAT_AUTORTS ((__force upstat_t) (1 << 2)) #define UPSTAT_AUTORTS ((__force upstat_t) (1 << 2))
#define UPSTAT_AUTOCTS ((__force upstat_t) (1 << 3)) #define UPSTAT_AUTOCTS ((__force upstat_t) (1 << 3))
#define UPSTAT_AUTOXOFF ((__force upstat_t) (1 << 4)) #define UPSTAT_AUTOXOFF ((__force upstat_t) (1 << 4))
#define UPSTAT_SYNC_FIFO ((__force upstat_t) (1 << 5))
int hw_stopped; /* sw-assisted CTS flow state */ int hw_stopped; /* sw-assisted CTS flow state */
unsigned int mctrl; /* current modem ctrl settings */ unsigned int mctrl; /* current modem ctrl settings */
@ -348,7 +349,8 @@ struct earlycon_device {
}; };
struct earlycon_id { struct earlycon_id {
char name[16]; char name[15];
char name_term; /* In case compiler didn't '\0' term name */
char compatible[128]; char compatible[128];
int (*setup)(struct earlycon_device *, const char *options); int (*setup)(struct earlycon_device *, const char *options);
}; };

View File

@ -13,7 +13,7 @@
*/ */
#define ASYNCB_HUP_NOTIFY 0 /* Notify getty on hangups and closes #define ASYNCB_HUP_NOTIFY 0 /* Notify getty on hangups and closes
* on the callout port */ * on the callout port */
#define ASYNCB_FOURPORT 1 /* Set OU1, OUT2 per AST Fourport settings */ #define ASYNCB_FOURPORT 1 /* Set OUT1, OUT2 per AST Fourport settings */
#define ASYNCB_SAK 2 /* Secure Attention Key (Orange book) */ #define ASYNCB_SAK 2 /* Secure Attention Key (Orange book) */
#define ASYNCB_SPLIT_TERMIOS 3 /* [x] Separate termios for dialin/callout */ #define ASYNCB_SPLIT_TERMIOS 3 /* [x] Separate termios for dialin/callout */
#define ASYNCB_SPD_HI 4 /* Use 57600 instead of 38400 bps */ #define ASYNCB_SPD_HI 4 /* Use 57600 instead of 38400 bps */