diff options
Diffstat (limited to 'drivers')
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 |