summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/tty/Kconfig24
-rw-r--r--drivers/tty/ipwireless/hardware.c2
-rw-r--r--drivers/tty/n_gsm.c231
-rw-r--r--drivers/tty/n_tty.c6
-rw-r--r--drivers/tty/serdev/serdev-ttyport.c4
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c13
-rw-r--r--drivers/tty/serial/8250/8250_of.c1
-rw-r--r--drivers/tty/serial/8250/8250_omap.c75
-rw-r--r--drivers/tty/serial/Kconfig22
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/clps711x.c23
-rw-r--r--drivers/tty/serial/fsl_lpuart.c208
-rw-r--r--drivers/tty/serial/lpc32xx_hs.c4
-rw-r--r--drivers/tty/serial/max310x.c21
-rw-r--r--drivers/tty/serial/meson_uart.c13
-rw-r--r--drivers/tty/serial/mps2-uart.c138
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c279
-rw-r--r--drivers/tty/serial/sc16is7xx.c4
-rw-r--r--drivers/tty/serial/sh-sci.c71
-rw-r--r--drivers/tty/serial/tegra-tcu.c298
-rw-r--r--drivers/tty/sysrq.c8
-rw-r--r--drivers/tty/tty_buffer.c2
-rw-r--r--drivers/tty/tty_io.c3
-rw-r--r--drivers/tty/tty_ldisc.c47
-rw-r--r--drivers/tty/vt/vc_screen.c48
-rw-r--r--drivers/tty/vt/vt.c62
26 files changed, 1114 insertions, 494 deletions
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index 0840d27381ea..e0a04bfc873e 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -441,4 +441,28 @@ config VCC
depends on SUN_LDOMS
help
Support for Sun logical domain consoles.
+
+config LDISC_AUTOLOAD
+ bool "Automatically load TTY Line Disciplines"
+ default y
+ help
+ Historically the kernel has always automatically loaded any
+ line discipline that is in a kernel module when a user asks
+ for it to be loaded with the TIOCSETD ioctl, or through other
+ means. This is not always the best thing to do on systems
+ where you know you will not be using some of the more
+ "ancient" line disciplines, so prevent the kernel from doing
+ this unless the request is coming from a process with the
+ CAP_SYS_MODULE permissions.
+
+ Say 'Y' here if you trust your userspace users to do the right
+ thing, or if you have only provided the line disciplines that
+ you know you will be using, or if you wish to continue to use
+ the traditional method of on-demand loading of these modules
+ by any user.
+
+ This functionality can be changed at runtime with the
+ dev.tty.ldisc_autoload sysctl, this configuration option will
+ only set the default value of this functionality.
+
endif # TTY
diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c
index b0baa4ce10f9..6bbf35682d53 100644
--- a/drivers/tty/ipwireless/hardware.c
+++ b/drivers/tty/ipwireless/hardware.c
@@ -1516,6 +1516,8 @@ static void ipw_send_setup_packet(struct ipw_hardware *hw)
sizeof(struct ipw_setup_get_version_query_packet),
ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP,
TL_SETUP_SIGNO_GET_VERSION_QRY);
+ if (!ver_packet)
+ return;
ver_packet->header.length = sizeof(struct tl_setup_get_version_qry);
/*
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 6f7da9a9d76f..d9662848a297 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -143,8 +143,8 @@ struct gsm_dlci {
struct sk_buff *skb; /* Frame being sent */
struct sk_buff_head skb_list; /* Queued frames */
/* Data handling callback */
- void (*data)(struct gsm_dlci *dlci, u8 *data, int len);
- void (*prev_data)(struct gsm_dlci *dlci, u8 *data, int len);
+ void (*data)(struct gsm_dlci *dlci, const u8 *data, int len);
+ void (*prev_data)(struct gsm_dlci *dlci, const u8 *data, int len);
struct net_device *net; /* network interface, if created */
};
@@ -988,7 +988,7 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
* Encode up and queue a UI/UIH frame containing our response.
*/
-static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data,
+static void gsm_control_reply(struct gsm_mux *gsm, int cmd, const u8 *data,
int dlen)
{
struct gsm_msg *msg;
@@ -1073,14 +1073,14 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
* and if need be stuff a break message down the tty.
*/
-static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
+static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
{
unsigned int addr = 0;
unsigned int modem = 0;
unsigned int brk = 0;
struct gsm_dlci *dlci;
int len = clen;
- u8 *dp = data;
+ const u8 *dp = data;
struct tty_struct *tty;
while (gsm_read_ea(&addr, *dp++) == 0) {
@@ -1134,13 +1134,13 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
* this into the uplink tty if present
*/
-static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
+static void gsm_control_rls(struct gsm_mux *gsm, const u8 *data, int clen)
{
struct tty_port *port;
unsigned int addr = 0;
u8 bits;
int len = clen;
- u8 *dp = data;
+ const u8 *dp = data;
while (gsm_read_ea(&addr, *dp++) == 0) {
len--;
@@ -1189,7 +1189,7 @@ static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
*/
static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
- u8 *data, int clen)
+ const u8 *data, int clen)
{
u8 buf[1];
unsigned long flags;
@@ -1261,7 +1261,7 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
*/
static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
- u8 *data, int clen)
+ const u8 *data, int clen)
{
struct gsm_control *ctrl;
unsigned long flags;
@@ -1553,7 +1553,7 @@ static void gsm_dlci_begin_close(struct gsm_dlci *dlci)
* open we shovel the bits down it, if not we drop them.
*/
-static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen)
+static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen)
{
/* krefs .. */
struct tty_port *port = &dlci->port;
@@ -1603,7 +1603,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen)
* and we divide up the work accordingly.
*/
-static void gsm_dlci_command(struct gsm_dlci *dlci, u8 *data, int len)
+static void gsm_dlci_command(struct gsm_dlci *dlci, const u8 *data, int len)
{
/* See what command is involved */
unsigned int command = 0;
@@ -2214,6 +2214,111 @@ static struct gsm_mux *gsm_alloc_mux(void)
return gsm;
}
+static void gsm_copy_config_values(struct gsm_mux *gsm,
+ struct gsm_config *c)
+{
+ memset(c, 0, sizeof(*c));
+ c->adaption = gsm->adaption;
+ c->encapsulation = gsm->encoding;
+ c->initiator = gsm->initiator;
+ c->t1 = gsm->t1;
+ c->t2 = gsm->t2;
+ c->t3 = 0; /* Not supported */
+ c->n2 = gsm->n2;
+ if (gsm->ftype == UIH)
+ c->i = 1;
+ else
+ c->i = 2;
+ pr_debug("Ftype %d i %d\n", gsm->ftype, c->i);
+ c->mru = gsm->mru;
+ c->mtu = gsm->mtu;
+ c->k = 0;
+}
+
+static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
+{
+ int need_close = 0;
+ int need_restart = 0;
+
+ /* Stuff we don't support yet - UI or I frame transport, windowing */
+ if ((c->adaption != 1 && c->adaption != 2) || c->k)
+ return -EOPNOTSUPP;
+ /* Check the MRU/MTU range looks sane */
+ if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
+ return -EINVAL;
+ if (c->n2 < 3)
+ return -EINVAL;
+ if (c->encapsulation > 1) /* Basic, advanced, no I */
+ return -EINVAL;
+ if (c->initiator > 1)
+ return -EINVAL;
+ if (c->i == 0 || c->i > 2) /* UIH and UI only */
+ return -EINVAL;
+ /*
+ * See what is needed for reconfiguration
+ */
+
+ /* Timing fields */
+ if (c->t1 != 0 && c->t1 != gsm->t1)
+ need_restart = 1;
+ if (c->t2 != 0 && c->t2 != gsm->t2)
+ need_restart = 1;
+ if (c->encapsulation != gsm->encoding)
+ need_restart = 1;
+ if (c->adaption != gsm->adaption)
+ need_restart = 1;
+ /* Requires care */
+ if (c->initiator != gsm->initiator)
+ need_close = 1;
+ if (c->mru != gsm->mru)
+ need_restart = 1;
+ if (c->mtu != gsm->mtu)
+ need_restart = 1;
+
+ /*
+ * Close down what is needed, restart and initiate the new
+ * configuration
+ */
+
+ if (need_close || need_restart) {
+ int ret;
+
+ ret = gsm_disconnect(gsm);
+
+ if (ret)
+ return ret;
+ }
+ if (need_restart)
+ gsm_cleanup_mux(gsm);
+
+ gsm->initiator = c->initiator;
+ gsm->mru = c->mru;
+ gsm->mtu = c->mtu;
+ gsm->encoding = c->encapsulation;
+ gsm->adaption = c->adaption;
+ gsm->n2 = c->n2;
+
+ if (c->i == 1)
+ gsm->ftype = UIH;
+ else if (c->i == 2)
+ gsm->ftype = UI;
+
+ if (c->t1)
+ gsm->t1 = c->t1;
+ if (c->t2)
+ gsm->t2 = c->t2;
+
+ /*
+ * FIXME: We need to separate activation/deactivation from adding
+ * and removing from the mux array
+ */
+ if (need_restart)
+ gsm_activate_mux(gsm);
+ if (gsm->initiator && need_close)
+ gsm_dlci_begin_open(gsm->dlci[0]);
+ return 0;
+}
+
/**
* gsmld_output - write to link
* @gsm: our mux
@@ -2495,89 +2600,6 @@ static __poll_t gsmld_poll(struct tty_struct *tty, struct file *file,
return mask;
}
-static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
- struct gsm_config *c)
-{
- int need_close = 0;
- int need_restart = 0;
-
- /* Stuff we don't support yet - UI or I frame transport, windowing */
- if ((c->adaption != 1 && c->adaption != 2) || c->k)
- return -EOPNOTSUPP;
- /* Check the MRU/MTU range looks sane */
- if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
- return -EINVAL;
- if (c->n2 < 3)
- return -EINVAL;
- if (c->encapsulation > 1) /* Basic, advanced, no I */
- return -EINVAL;
- if (c->initiator > 1)
- return -EINVAL;
- if (c->i == 0 || c->i > 2) /* UIH and UI only */
- return -EINVAL;
- /*
- * See what is needed for reconfiguration
- */
-
- /* Timing fields */
- if (c->t1 != 0 && c->t1 != gsm->t1)
- need_restart = 1;
- if (c->t2 != 0 && c->t2 != gsm->t2)
- need_restart = 1;
- if (c->encapsulation != gsm->encoding)
- need_restart = 1;
- if (c->adaption != gsm->adaption)
- need_restart = 1;
- /* Requires care */
- if (c->initiator != gsm->initiator)
- need_close = 1;
- if (c->mru != gsm->mru)
- need_restart = 1;
- if (c->mtu != gsm->mtu)
- need_restart = 1;
-
- /*
- * Close down what is needed, restart and initiate the new
- * configuration
- */
-
- if (need_close || need_restart) {
- int ret;
-
- ret = gsm_disconnect(gsm);
-
- if (ret)
- return ret;
- }
- if (need_restart)
- gsm_cleanup_mux(gsm);
-
- gsm->initiator = c->initiator;
- gsm->mru = c->mru;
- gsm->mtu = c->mtu;
- gsm->encoding = c->encapsulation;
- gsm->adaption = c->adaption;
- gsm->n2 = c->n2;
-
- if (c->i == 1)
- gsm->ftype = UIH;
- else if (c->i == 2)
- gsm->ftype = UI;
-
- if (c->t1)
- gsm->t1 = c->t1;
- if (c->t2)
- gsm->t2 = c->t2;
-
- /* FIXME: We need to separate activation/deactivation from adding
- and removing from the mux array */
- if (need_restart)
- gsm_activate_mux(gsm);
- if (gsm->initiator && need_close)
- gsm_dlci_begin_open(gsm->dlci[0]);
- return 0;
-}
-
static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -2586,29 +2608,14 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
switch (cmd) {
case GSMIOC_GETCONF:
- memset(&c, 0, sizeof(c));
- c.adaption = gsm->adaption;
- c.encapsulation = gsm->encoding;
- c.initiator = gsm->initiator;
- c.t1 = gsm->t1;
- c.t2 = gsm->t2;
- c.t3 = 0; /* Not supported */
- c.n2 = gsm->n2;
- if (gsm->ftype == UIH)
- c.i = 1;
- else
- c.i = 2;
- pr_debug("Ftype %d i %d\n", gsm->ftype, c.i);
- c.mru = gsm->mru;
- c.mtu = gsm->mtu;
- c.k = 0;
+ gsm_copy_config_values(gsm, &c);
if (copy_to_user((void *)arg, &c, sizeof(c)))
return -EFAULT;
return 0;
case GSMIOC_SETCONF:
if (copy_from_user(&c, (void *)arg, sizeof(c)))
return -EFAULT;
- return gsmld_config(tty, gsm, &c);
+ return gsm_config(gsm, &c);
default:
return n_tty_ioctl_helper(tty, file, cmd, arg);
}
@@ -2695,7 +2702,7 @@ static void gsm_mux_net_tx_timeout(struct net_device *net)
}
static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,
- unsigned char *in_buf, int size)
+ const unsigned char *in_buf, int size)
{
struct net_device *net = dlci->net;
struct sk_buff *skb;
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 5dc9686697cf..9cdb0fa3c4bf 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -50,8 +50,10 @@
#include <linux/ratelimit.h>
#include <linux/vmalloc.h>
-
-/* number of characters left in xmit buffer before select has we have room */
+/*
+ * Until this number of characters is queued in the xmit buffer, select will
+ * return "we have room for writes".
+ */
#define WAKEUP_CHARS 256
/*
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index fa1672993b4c..d1cdd2ab8b4c 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -233,7 +233,7 @@ static int ttyport_get_tiocm(struct serdev_controller *ctrl)
if (!tty->ops->tiocmget)
return -ENOTSUPP;
- return tty->driver->ops->tiocmget(tty);
+ return tty->ops->tiocmget(tty);
}
static int ttyport_set_tiocm(struct serdev_controller *ctrl, unsigned int set, unsigned int clear)
@@ -244,7 +244,7 @@ static int ttyport_set_tiocm(struct serdev_controller *ctrl, unsigned int set, u
if (!tty->ops->tiocmset)
return -ENOTSUPP;
- return tty->driver->ops->tiocmset(tty, set, clear);
+ return tty->ops->tiocmset(tty, set, clear);
}
static const struct serdev_controller_ops ctrl_ops = {
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index 15a8c8dfa92b..424c07c5f629 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -129,22 +129,21 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev,
return 0;
}
-EARLYCON_DECLARE(jz4740_uart, ingenic_early_console_setup);
OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart",
ingenic_early_console_setup);
-EARLYCON_DECLARE(jz4770_uart, ingenic_early_console_setup);
OF_EARLYCON_DECLARE(jz4770_uart, "ingenic,jz4770-uart",
ingenic_early_console_setup);
-EARLYCON_DECLARE(jz4775_uart, ingenic_early_console_setup);
OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart",
ingenic_early_console_setup);
-EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup);
OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart",
ingenic_early_console_setup);
+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)
{
int ier;
@@ -328,12 +327,18 @@ static const struct ingenic_uart_config jz4780_uart_config = {
.fifosize = 64,
};
+static const struct ingenic_uart_config x1000_uart_config = {
+ .tx_loadsz = 32,
+ .fifosize = 64,
+};
+
static const struct of_device_id of_match[] = {
{ .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config },
{ .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config },
{ .compatible = "ingenic,jz4770-uart", .data = &jz4760_uart_config },
{ .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config },
{ .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config },
+ { .compatible = "ingenic,x1000-uart", .data = &x1000_uart_config },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match);
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index a1a85805d010..17da8af36aa1 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -327,6 +327,7 @@ static const struct of_device_id of_platform_serial_table[] = {
{ .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, },
{ .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, },
{ .compatible = "ralink,rt2880-uart", .data = (void *)PORT_RT2880, },
+ { .compatible = "intel,xscale-uart", .data = (void *)PORT_XSCALE, },
{ .compatible = "altr,16550-FIFO32",
.data = (void *)PORT_ALTR_16550_F32, },
{ .compatible = "altr,16550-FIFO64",
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index ad7ba7d0f28d..0a8316632d75 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -12,6 +12,7 @@
#define SUPPORT_SYSRQ
#endif
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -1134,10 +1135,12 @@ static int omap8250_probe(struct platform_device *pdev)
{
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ struct device_node *np = pdev->dev.of_node;
struct omap8250_priv *priv;
struct uart_8250_port up;
int ret;
void __iomem *membase;
+ const struct of_device_id *id;
if (!regs || !irq) {
dev_err(&pdev->dev, "missing registers or irq\n");
@@ -1194,27 +1197,31 @@ static int omap8250_probe(struct platform_device *pdev)
up.port.unthrottle = omap_8250_unthrottle;
up.port.rs485_config = omap_8250_rs485_config;
- if (pdev->dev.of_node) {
- const struct of_device_id *id;
-
- ret = of_alias_get_id(pdev->dev.of_node, "serial");
-
- of_property_read_u32(pdev->dev.of_node, "clock-frequency",
- &up.port.uartclk);
- priv->wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1);
-
- id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev);
- if (id && id->data)
- priv->habit |= *(u8 *)id->data;
- } else {
- ret = pdev->id;
- }
+ ret = of_alias_get_id(np, "serial");
if (ret < 0) {
- dev_err(&pdev->dev, "failed to get alias/pdev id\n");
+ dev_err(&pdev->dev, "failed to get alias\n");
return ret;
}
up.port.line = ret;
+ if (of_property_read_u32(np, "clock-frequency", &up.port.uartclk)) {
+ struct clk *clk;
+
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ if (PTR_ERR(clk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ } else {
+ up.port.uartclk = clk_get_rate(clk);
+ }
+ }
+
+ priv->wakeirq = irq_of_parse_and_map(np, 1);
+
+ id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev);
+ if (id && id->data)
+ priv->habit |= *(u8 *)id->data;
+
if (!up.port.uartclk) {
up.port.uartclk = DEFAULT_CLK_SPEED;
dev_warn(&pdev->dev,
@@ -1242,25 +1249,23 @@ static int omap8250_probe(struct platform_device *pdev)
omap_serial_fill_features_erratas(&up, priv);
up.port.handle_irq = omap8250_no_handle_irq;
#ifdef CONFIG_SERIAL_8250_DMA
- if (pdev->dev.of_node) {
- /*
- * Oh DMA support. If there are no DMA properties in the DT then
- * we will fall back to a generic DMA channel which does not
- * really work here. To ensure that we do not get a generic DMA
- * channel assigned, we have the the_no_dma_filter_fn() here.
- * To avoid "failed to request DMA" messages we check for DMA
- * properties in DT.
- */
- ret = of_property_count_strings(pdev->dev.of_node, "dma-names");
- if (ret == 2) {
- up.dma = &priv->omap8250_dma;
- priv->omap8250_dma.fn = the_no_dma_filter_fn;
- priv->omap8250_dma.tx_dma = omap_8250_tx_dma;
- priv->omap8250_dma.rx_dma = omap_8250_rx_dma;
- priv->omap8250_dma.rx_size = RX_TRIGGER;
- priv->omap8250_dma.rxconf.src_maxburst = RX_TRIGGER;
- priv->omap8250_dma.txconf.dst_maxburst = TX_TRIGGER;
- }
+ /*
+ * Oh DMA support. If there are no DMA properties in the DT then
+ * we will fall back to a generic DMA channel which does not
+ * really work here. To ensure that we do not get a generic DMA
+ * channel assigned, we have the the_no_dma_filter_fn() here.
+ * To avoid "failed to request DMA" messages we check for DMA
+ * properties in DT.
+ */
+ ret = of_property_count_strings(np, "dma-names");
+ if (ret == 2) {
+ up.dma = &priv->omap8250_dma;
+ priv->omap8250_dma.fn = the_no_dma_filter_fn;
+ priv->omap8250_dma.tx_dma = omap_8250_tx_dma;
+ priv->omap8250_dma.rx_dma = omap_8250_rx_dma;
+ priv->omap8250_dma.rx_size = RX_TRIGGER;
+ priv->omap8250_dma.rxconf.src_maxburst = RX_TRIGGER;
+ priv->omap8250_dma.txconf.dst_maxburst = TX_TRIGGER;
}
#endif
ret = serial8250_register_8250_port(&up);
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 089a6f285d5e..72966bc0ac76 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -335,6 +335,28 @@ config SERIAL_TEGRA
are enabled). This driver uses the APB DMA to achieve higher baudrate
and better performance.
+config SERIAL_TEGRA_TCU
+ tristate "NVIDIA Tegra Combined UART"
+ depends on ARCH_TEGRA && TEGRA_HSP_MBOX
+ select SERIAL_CORE
+ help
+ Support for the mailbox-based TCU (Tegra Combined UART) serial port.
+ TCU is a virtual serial port that allows multiplexing multiple data
+ streams into a single hardware serial port.
+
+config SERIAL_TEGRA_TCU_CONSOLE
+ bool "Support for console on a Tegra TCU serial port"
+ depends on SERIAL_TEGRA_TCU=y
+ select SERIAL_CORE_CONSOLE
+ default y
+ ---help---
+ If you say Y here, it will be possible to use a the Tegra TCU as the
+ system console (the system console is the device which receives all
+ kernel messages and warnings and which allows logins in single user
+ mode).
+
+ If unsure, say Y.
+
config SERIAL_MAX3100
tristate "MAX3100 support"
depends on SPI
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 1511e8a9f856..40b702aaa85e 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o
+obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o
obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o
obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
obj-$(CONFIG_SERIAL_ARC) += arc_uart.o
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 98f193a83392..061590795680 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -442,14 +442,10 @@ static struct console clps711x_console = {
static int uart_clps711x_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- int ret, index = np ? of_alias_get_id(np, "serial") : pdev->id;
struct clps711x_port *s;
struct resource *res;
struct clk *uart_clk;
- int irq;
-
- if (index < 0 || index >= UART_CLPS711X_NR)
- return -EINVAL;
+ int irq, ret;
s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
if (!s)
@@ -473,20 +469,11 @@ static int uart_clps711x_probe(struct platform_device *pdev)
if (s->rx_irq < 0)
return s->rx_irq;
- if (!np) {
- char syscon_name[9];
-
- sprintf(syscon_name, "syscon.%i", index + 1);
- s->syscon = syscon_regmap_lookup_by_pdevname(syscon_name);
- if (IS_ERR(s->syscon))
- return PTR_ERR(s->syscon);
- } else {
- s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon");
- if (IS_ERR(s->syscon))
- return PTR_ERR(s->syscon);
- }
+ s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon");
+ if (IS_ERR(s->syscon))
+ return PTR_ERR(s->syscon);
- s->port.line = index;
+ s->port.line = of_alias_get_id(np, "serial");
s->port.dev = &pdev->dev;
s->port.iotype = UPIO_MEM32;
s->port.mapbase = res->start;
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index debdd1b9e01a..ea1c85e3b432 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -426,6 +426,17 @@ static void lpuart_dma_tx_complete(void *arg)
spin_unlock_irqrestore(&sport->port.lock, flags);
}
+static dma_addr_t lpuart_dma_datareg_addr(struct lpuart_port *sport)
+{
+ switch (sport->port.iotype) {
+ case UPIO_MEM32:
+ return sport->port.mapbase + UARTDATA;
+ case UPIO_MEM32BE:
+ return sport->port.mapbase + UARTDATA + sizeof(u32) - 1;
+ }
+ return sport->port.mapbase + UARTDR;
+}
+
static int lpuart_dma_tx_request(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
@@ -433,7 +444,7 @@ static int lpuart_dma_tx_request(struct uart_port *port)
struct dma_slave_config dma_tx_sconfig = {};
int ret;
- dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR;
+ dma_tx_sconfig.dst_addr = lpuart_dma_datareg_addr(sport);
dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma_tx_sconfig.dst_maxburst = 1;
dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
@@ -636,13 +647,19 @@ static void lpuart_start_tx(struct uart_port *port)
static void lpuart32_start_tx(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+ struct circ_buf *xmit = &sport->port.state->xmit;
unsigned long temp;
- temp = lpuart32_read(port, UARTCTRL);
- lpuart32_write(port, temp | UARTCTRL_TIE, UARTCTRL);
+ if (sport->lpuart_dma_tx_use) {
+ if (!uart_circ_empty(xmit) && !uart_tx_stopped(port))
+ lpuart_dma_tx(sport);
+ } else {
+ temp = lpuart32_read(port, UARTCTRL);
+ lpuart32_write(port, temp | UARTCTRL_TIE, UARTCTRL);
- if (lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE)
- lpuart32_transmit_buffer(sport);
+ if (lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE)
+ lpuart32_transmit_buffer(sport);
+ }
}
/* return TIOCSER_TEMT when transmitter is not busy */
@@ -664,8 +681,18 @@ static unsigned int lpuart_tx_empty(struct uart_port *port)
static unsigned int lpuart32_tx_empty(struct uart_port *port)
{
- return (lpuart32_read(port, UARTSTAT) & UARTSTAT_TC) ?
- TIOCSER_TEMT : 0;
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ unsigned long stat = lpuart32_read(port, UARTSTAT);
+ unsigned long sfifo = lpuart32_read(port, UARTFIFO);
+
+ if (sport->dma_tx_in_progress)
+ return 0;
+
+ if (stat & UARTSTAT_TC && sfifo & UARTFIFO_TXEMPT)
+ return TIOCSER_TEMT;
+
+ return 0;
}
static bool lpuart_is_32(struct lpuart_port *sport)
@@ -862,11 +889,10 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
rxcount = lpuart32_read(&sport->port, UARTWATER);
rxcount = rxcount >> UARTWATER_RXCNT_OFF;
- if (sts & UARTSTAT_RDRF || rxcount > 0)
+ if ((sts & UARTSTAT_RDRF || rxcount > 0) && !sport->lpuart_dma_rx_use)
lpuart32_rxint(irq, dev_id);
- if ((sts & UARTSTAT_TDRE) &&
- !(lpuart32_read(&sport->port, UARTBAUD) & UARTBAUD_TDMAE))
+ if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use)
lpuart_txint(irq, dev_id);
lpuart32_write(&sport->port, sts, UARTSTAT);
@@ -881,18 +907,31 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
struct circ_buf *ring = &sport->rx_ring;
unsigned long flags;
int count = 0;
- unsigned char sr;
- sr = readb(sport->port.membase + UARTSR1);
+ if (lpuart_is_32(sport)) {
+ unsigned long sr = lpuart32_read(&sport->port, UARTSTAT);
- if (sr & (UARTSR1_PE | UARTSR1_FE)) {
- /* Read DR to clear the error flags */
- readb(sport->port.membase + UARTDR);
+ if (sr & (UARTSTAT_PE | UARTSTAT_FE)) {
+ /* Read DR to clear the error flags */
+ lpuart32_read(&sport->port, UARTDATA);
+
+ if (sr & UARTSTAT_PE)
+ sport->port.icount.parity++;
+ else if (sr & UARTSTAT_FE)
+ sport->port.icount.frame++;
+ }
+ } else {
+ unsigned char sr = readb(sport->port.membase + UARTSR1);
- if (sr & UARTSR1_PE)
- sport->port.icount.parity++;
- else if (sr & UARTSR1_FE)
- sport->port.icount.frame++;
+ if (sr & (UARTSR1_PE | UARTSR1_FE)) {
+ /* Read DR to clear the error flags */
+ readb(sport->port.membase + UARTDR);
+
+ if (sr & UARTSR1_PE)
+ sport->port.icount.parity++;
+ else if (sr & UARTSR1_FE)
+ sport->port.icount.frame++;
+ }
}
async_tx_ack(sport->dma_rx_desc);
@@ -1015,7 +1054,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
return -EINVAL;
}
- dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR;
+ dma_rx_sconfig.src_addr = lpuart_dma_datareg_addr(sport);
dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma_rx_sconfig.src_maxburst = 1;
dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
@@ -1043,8 +1082,14 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc);
dma_async_issue_pending(sport->dma_rx_chan);
- writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS,
- sport->port.membase + UARTCR5);
+ if (lpuart_is_32(sport)) {
+ unsigned long temp = lpuart