diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-04 05:11:49 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-04 05:11:49 +0200 |
commit | e6dce825fba05f447bd22c865e27233182ab3d79 (patch) | |
tree | 266c22686f5b376f2e1d560baaf596e7fd5b9c98 /drivers | |
parent | Merge tag 'driver-core-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/... (diff) | |
parent | Revert "serial: pl011: add console matching function" (diff) | |
download | linux-e6dce825fba05f447bd22c865e27233182ab3d79.tar.xz linux-e6dce825fba05f447bd22c865e27233182ab3d79.zip |
Merge tag 'tty-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty and serial updates from Greg KH:
"Here is the big tty and serial patch set for 4.9-rc1.
It also includes some drivers/dma/ changes, as those were needed by
some serial drivers, and they were all acked by the DMA maintainer.
Also in here is the long-suffering ACPI SPCR patchset, which was
passed around from maintainer to maintainer like a hot-potato. Seems I
was the sucker^Wlucky one. All of those patches have been acked by the
various subsystem maintainers as well.
All of this has been in linux-next with no reported issues"
* tag 'tty-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (111 commits)
Revert "serial: pl011: add console matching function"
MAINTAINERS: update entry for atmel_serial driver
serial: pl011: add console matching function
ARM64: ACPI: enable ACPI_SPCR_TABLE
ACPI: parse SPCR and enable matching console
of/serial: move earlycon early_param handling to serial
Revert "drivers/tty: Explicitly pass current to show_stack"
tty: amba-pl011: Don't complain on -EPROBE_DEFER when no irq
nios2: dts: 10m50: Add tx-threshold parameter
serial: 8250: Set Altera 16550 TX FIFO Threshold
serial: 8250: of: Load TX FIFO Threshold from DT
Documentation: dt: serial: Add TX FIFO threshold parameter
drivers/tty: Explicitly pass current to show_stack
serial: imx: Fix DCD reading
serial: stm32: mark symbols static where possible
serial: xuartps: Add some register initialisation to cdns_early_console_setup()
serial: xuartps: Removed unwanted checks while reading the error conditions
serial: xuartps: Rewrite the interrupt handling logic
serial: stm32: use mapbase instead of membase for DMA
tty/serial: atmel: fix fractional baud rate computation
...
Diffstat (limited to 'drivers')
51 files changed, 2455 insertions, 1205 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 33201d4de633..535e7828445a 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -77,6 +77,9 @@ config ACPI_DEBUGGER_USER endif +config ACPI_SPCR_TABLE + bool + config ACPI_SLEEP bool depends on SUSPEND || HIBERNATION diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 313f970888e4..9ed087853dee 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o obj-$(CONFIG_ACPI_BGRT) += bgrt.o obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o +obj-$(CONFIG_ACPI_SPCR_TABLE) += spcr.o obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o # processor has its own "processor." module_param namespace diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c new file mode 100644 index 000000000000..e8d7bc7d4da8 --- /dev/null +++ b/drivers/acpi/spcr.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2012, Intel Corporation + * Copyright (c) 2015, Red Hat, Inc. + * Copyright (c) 2015, 2016 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#define pr_fmt(fmt) "ACPI: SPCR: " fmt + +#include <linux/acpi.h> +#include <linux/console.h> +#include <linux/kernel.h> +#include <linux/serial_core.h> + +/** + * parse_spcr() - parse ACPI SPCR table and add preferred console + * + * @earlycon: set up earlycon for the console specified by the table + * + * For the architectures with support for ACPI, CONFIG_ACPI_SPCR_TABLE may be + * defined to parse ACPI SPCR table. As a result of the parsing preferred + * console is registered and if @earlycon is true, earlycon is set up. + * + * When CONFIG_ACPI_SPCR_TABLE is defined, this function should be called + * from arch inintialization code as soon as the DT/ACPI decision is made. + * + */ +int __init parse_spcr(bool earlycon) +{ + static char opts[64]; + struct acpi_table_spcr *table; + acpi_size table_size; + acpi_status status; + char *uart; + char *iotype; + int baud_rate; + int err; + + if (acpi_disabled) + return -ENODEV; + + status = acpi_get_table_with_size(ACPI_SIG_SPCR, 0, + (struct acpi_table_header **)&table, + &table_size); + + if (ACPI_FAILURE(status)) + return -ENOENT; + + if (table->header.revision < 2) { + err = -ENOENT; + pr_err("wrong table version\n"); + goto done; + } + + iotype = table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY ? + "mmio" : "io"; + + switch (table->interface_type) { + case ACPI_DBG2_ARM_SBSA_32BIT: + iotype = "mmio32"; + /* fall through */ + case ACPI_DBG2_ARM_PL011: + case ACPI_DBG2_ARM_SBSA_GENERIC: + case ACPI_DBG2_BCM2835: + uart = "pl011"; + break; + case ACPI_DBG2_16550_COMPATIBLE: + case ACPI_DBG2_16550_SUBSET: + uart = "uart"; + break; + default: + err = -ENOENT; + goto done; + } + + switch (table->baud_rate) { + case 3: + baud_rate = 9600; + break; + case 4: + baud_rate = 19200; + break; + case 6: + baud_rate = 57600; + break; + case 7: + baud_rate = 115200; + break; + default: + err = -ENOENT; + goto done; + } + + snprintf(opts, sizeof(opts), "%s,%s,0x%llx,%d", uart, iotype, + table->serial_port.address, baud_rate); + + pr_info("console: %s\n", opts); + + if (earlycon) + setup_earlycon(opts); + + err = add_preferred_console(uart, 0, opts + strlen(uart) + 1); + +done: + early_acpi_os_unmap_memory((void __iomem *)table, table_size); + return err; +} diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index edf053f73a49..da18b18561c4 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -46,9 +46,9 @@ u8 _dmsize = _is_slave ? _sconfig->dst_maxburst : \ DW_DMA_MSIZE_16; \ u8 _dms = (_dwc->direction == DMA_MEM_TO_DEV) ? \ - _dwc->p_master : _dwc->m_master; \ + _dwc->dws.p_master : _dwc->dws.m_master; \ u8 _sms = (_dwc->direction == DMA_DEV_TO_MEM) ? \ - _dwc->p_master : _dwc->m_master; \ + _dwc->dws.p_master : _dwc->dws.m_master; \ \ (DWC_CTLL_DST_MSIZE(_dmsize) \ | DWC_CTLL_SRC_MSIZE(_smsize) \ @@ -143,12 +143,16 @@ static void dwc_initialize(struct dw_dma_chan *dwc) struct dw_dma *dw = to_dw_dma(dwc->chan.device); u32 cfghi = DWC_CFGH_FIFO_MODE; u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority); + bool hs_polarity = dwc->dws.hs_polarity; if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags)) return; - cfghi |= DWC_CFGH_DST_PER(dwc->dst_id); - cfghi |= DWC_CFGH_SRC_PER(dwc->src_id); + cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id); + cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id); + + /* Set polarity of handshake interface */ + cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0; channel_writel(dwc, CFG_LO, cfglo); channel_writel(dwc, CFG_HI, cfghi); @@ -209,7 +213,7 @@ static inline void dwc_do_single_block(struct dw_dma_chan *dwc, static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first) { struct dw_dma *dw = to_dw_dma(dwc->chan.device); - u8 lms = DWC_LLP_LMS(dwc->m_master); + u8 lms = DWC_LLP_LMS(dwc->dws.m_master); unsigned long was_soft_llp; /* ASSERT: channel is idle */ @@ -662,7 +666,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, struct dw_desc *prev; size_t xfer_count; size_t offset; - u8 m_master = dwc->m_master; + u8 m_master = dwc->dws.m_master; unsigned int src_width; unsigned int dst_width; unsigned int data_width = dw->pdata->data_width[m_master]; @@ -740,7 +744,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, struct dw_desc *prev; struct dw_desc *first; u32 ctllo; - u8 m_master = dwc->m_master; + u8 m_master = dwc->dws.m_master; u8 lms = DWC_LLP_LMS(m_master); dma_addr_t reg; unsigned int reg_width; @@ -895,12 +899,7 @@ bool dw_dma_filter(struct dma_chan *chan, void *param) return false; /* We have to copy data since dws can be temporary storage */ - - dwc->src_id = dws->src_id; - dwc->dst_id = dws->dst_id; - - dwc->m_master = dws->m_master; - dwc->p_master = dws->p_master; + memcpy(&dwc->dws, dws, sizeof(struct dw_dma_slave)); return true; } @@ -1167,11 +1166,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan) spin_lock_irqsave(&dwc->lock, flags); /* Clear custom channel configuration */ - dwc->src_id = 0; - dwc->dst_id = 0; - - dwc->m_master = 0; - dwc->p_master = 0; + memset(&dwc->dws, 0, sizeof(struct dw_dma_slave)); clear_bit(DW_DMA_IS_INITIALIZED, &dwc->flags); @@ -1264,7 +1259,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, struct dw_cyclic_desc *retval = NULL; struct dw_desc *desc; struct dw_desc *last = NULL; - u8 lms = DWC_LLP_LMS(dwc->m_master); + u8 lms = DWC_LLP_LMS(dwc->dws.m_master); unsigned long was_cyclic; unsigned int reg_width; unsigned int periods; @@ -1576,11 +1571,7 @@ int dw_dma_probe(struct dw_dma_chip *chip) (dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0; } else { dwc->block_size = pdata->block_size; - - /* Check if channel supports multi block transfer */ - channel_writel(dwc, LLP, DWC_LLP_LOC(0xffffffff)); - dwc->nollp = DWC_LLP_LOC(channel_readl(dwc, LLP)) == 0; - channel_writel(dwc, LLP, 0); + dwc->nollp = pdata->is_nollp; } } diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h index 4b7bd7834046..f65dd104479f 100644 --- a/drivers/dma/dw/regs.h +++ b/drivers/dma/dw/regs.h @@ -245,10 +245,7 @@ struct dw_dma_chan { bool nollp; /* custom slave configuration */ - u8 src_id; - u8 dst_id; - u8 m_master; - u8 p_master; + struct dw_dma_slave dws; /* configuration passed via .device_config */ struct dma_slave_config dma_sconfig; diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c index c5f21efd6090..29d04ca71d52 100644 --- a/drivers/dma/hsu/hsu.c +++ b/drivers/dma/hsu/hsu.c @@ -200,10 +200,9 @@ EXPORT_SYMBOL_GPL(hsu_dma_get_status); * is not a normal timeout interrupt, ie. hsu_dma_get_status() returned 0. * * Return: - * IRQ_NONE for invalid channel number, IRQ_HANDLED otherwise. + * 0 for invalid channel number, 1 otherwise. */ -irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, - u32 status) +int hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, u32 status) { struct hsu_dma_chan *hsuc; struct hsu_dma_desc *desc; @@ -211,7 +210,7 @@ irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, /* Sanity check */ if (nr >= chip->hsu->nr_channels) - return IRQ_NONE; + return 0; hsuc = &chip->hsu->chan[nr]; @@ -230,7 +229,7 @@ irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, } spin_unlock_irqrestore(&hsuc->vchan.lock, flags); - return IRQ_HANDLED; + return 1; } EXPORT_SYMBOL_GPL(hsu_dma_do_irq); diff --git a/drivers/dma/hsu/pci.c b/drivers/dma/hsu/pci.c index 9916058531d9..b51639f045ed 100644 --- a/drivers/dma/hsu/pci.c +++ b/drivers/dma/hsu/pci.c @@ -29,7 +29,7 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev) u32 dmaisr; u32 status; unsigned short i; - irqreturn_t ret = IRQ_NONE; + int ret = 0; int err; dmaisr = readl(chip->regs + HSU_PCI_DMAISR); @@ -37,14 +37,14 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev) if (dmaisr & 0x1) { err = hsu_dma_get_status(chip, i, &status); if (err > 0) - ret |= IRQ_HANDLED; + ret |= 1; else if (err == 0) ret |= hsu_dma_do_irq(chip, i, status); } dmaisr >>= 1; } - return ret; + return IRQ_RETVAL(ret); } static int hsu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 03ec76fc22ff..3cb47386fbb9 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -648,15 +648,11 @@ static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event) writel_relaxed(val, sdma->regs + chnenbl); } -static void sdma_handle_channel_loop(struct sdma_channel *sdmac) -{ - if (sdmac->desc.callback) - sdmac->desc.callback(sdmac->desc.callback_param); -} - static void sdma_update_channel_loop(struct sdma_channel *sdmac) { struct sdma_buffer_descriptor *bd; + int error = 0; + enum dma_status old_status = sdmac->status; /* * loop mode. Iterate over descriptors, re-setup them and @@ -668,17 +664,42 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac) if (bd->mode.status & BD_DONE) break; - if (bd->mode.status & BD_RROR) + if (bd->mode.status & BD_RROR) { + bd->mode.status &= ~BD_RROR; sdmac->status = DMA_ERROR; + error = -EIO; + } + + /* + * We use bd->mode.count to calculate the residue, since contains + * the number of bytes present in the current buffer descriptor. + */ + sdmac->chn_real_count = bd->mode.count; bd->mode.status |= BD_DONE; + bd->mode.count = sdmac->period_len; + + /* + * The callback is called from the interrupt context in order + * to reduce latency and to avoid the risk of altering the + * SDMA transaction status by the time the client tasklet is + * executed. + */ + + if (sdmac->desc.callback) + sdmac->desc.callback(sdmac->desc.callback_param); + sdmac->buf_tail++; sdmac->buf_tail %= sdmac->num_bd; + + if (error) + sdmac->status = old_status; } } -static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac) +static void mxc_sdma_handle_channel_normal(unsigned long data) { + struct sdma_channel *sdmac = (struct sdma_channel *) data; struct sdma_buffer_descriptor *bd; int i, error = 0; @@ -705,16 +726,6 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac) sdmac->desc.callback(sdmac->desc.callback_param); } -static void sdma_tasklet(unsigned long data) -{ - struct sdma_channel *sdmac = (struct sdma_channel *) data; - - if (sdmac->flags & IMX_DMA_SG_LOOP) - sdma_handle_channel_loop(sdmac); - else - mxc_sdma_handle_channel_normal(sdmac); -} - static irqreturn_t sdma_int_handler(int irq, void *dev_id) { struct sdma_engine *sdma = dev_id; @@ -731,8 +742,8 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id) if (sdmac->flags & IMX_DMA_SG_LOOP) sdma_update_channel_loop(sdmac); - - tasklet_schedule(&sdmac->tasklet); + else + tasklet_schedule(&sdmac->tasklet); __clear_bit(channel, &stat); } @@ -1353,7 +1364,8 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan, u32 residue; if (sdmac->flags & IMX_DMA_SG_LOOP) - residue = (sdmac->num_bd - sdmac->buf_tail) * sdmac->period_len; + residue = (sdmac->num_bd - sdmac->buf_tail) * + sdmac->period_len - sdmac->chn_real_count; else residue = sdmac->chn_count - sdmac->chn_real_count; @@ -1732,7 +1744,7 @@ static int sdma_probe(struct platform_device *pdev) dma_cookie_init(&sdmac->chan); sdmac->channel = i; - tasklet_init(&sdmac->tasklet, sdma_tasklet, + tasklet_init(&sdmac->tasklet, mxc_sdma_handle_channel_normal, (unsigned long) sdmac); /* * Add the channel to the DMAC list. Do not add channel 0 though diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 085c6389afd1..c89d5d231a0e 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -924,7 +924,7 @@ static inline void early_init_dt_check_for_initrd(unsigned long node) #ifdef CONFIG_SERIAL_EARLYCON -static int __init early_init_dt_scan_chosen_serial(void) +int __init early_init_dt_scan_chosen_stdout(void) { int offset; const char *p, *q, *options = NULL; @@ -968,15 +968,6 @@ static int __init early_init_dt_scan_chosen_serial(void) } return -ENODEV; } - -static int __init setup_of_earlycon(char *buf) -{ - if (buf) - return 0; - - return early_init_dt_scan_chosen_serial(); -} -early_param("earlycon", setup_of_earlycon); #endif /** diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 51e0d32883ba..a23fa5ed1d67 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -800,7 +800,7 @@ out_free_file: return retval; } -static struct file_operations ptmx_fops; +static struct file_operations ptmx_fops __ro_after_init; static void __init unix98_pty_init(void) { diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 1a16feac9a36..a697a8585ddc 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -31,6 +31,11 @@ struct uart_8250_dma { struct dma_chan *rxchan; struct dma_chan *txchan; + /* Device address base for DMA operations */ + phys_addr_t rx_dma_addr; + phys_addr_t tx_dma_addr; + + /* DMA address of the buffer in memory */ dma_addr_t rx_addr; dma_addr_t tx_addr; diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index dcf43f66404f..240a361b674f 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -639,7 +639,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx, { char match[] = "uart"; /* 8250-specific earlycon name */ unsigned char iotype; - unsigned long addr; + resource_size_t addr; int i; if (strncmp(name, match, 4) != 0) diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index 3590d012001f..fdbddbc6375d 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -142,7 +142,7 @@ void serial8250_rx_dma_flush(struct uart_8250_port *p) if (dma->rx_running) { dmaengine_pause(dma->rxchan); __dma_rx_complete(p); - dmaengine_terminate_all(dma->rxchan); + dmaengine_terminate_async(dma->rxchan); } } EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush); @@ -150,6 +150,10 @@ EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush); int serial8250_request_dma(struct uart_8250_port *p) { struct uart_8250_dma *dma = p->dma; + phys_addr_t rx_dma_addr = dma->rx_dma_addr ? + dma->rx_dma_addr : p->port.mapbase; + phys_addr_t tx_dma_addr = dma->tx_dma_addr ? + dma->tx_dma_addr : p->port.mapbase; dma_cap_mask_t mask; struct dma_slave_caps caps; int ret; @@ -157,11 +161,11 @@ int serial8250_request_dma(struct uart_8250_port *p) /* Default slave configuration parameters */ dma->rxconf.direction = DMA_DEV_TO_MEM; dma->rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - dma->rxconf.src_addr = p->port.mapbase + UART_RX; + dma->rxconf.src_addr = rx_dma_addr + UART_RX; dma->txconf.direction = DMA_MEM_TO_DEV; dma->txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - dma->txconf.dst_addr = p->port.mapbase + UART_TX; + dma->txconf.dst_addr = tx_dma_addr + UART_TX; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); @@ -247,14 +251,14 @@ void serial8250_release_dma(struct uart_8250_port *p) return; /* Release RX resources */ - dmaengine_terminate_all(dma->rxchan); + dmaengine_terminate_sync(dma->rxchan); dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf, dma->rx_addr); dma_release_channel(dma->rxchan); dma->rxchan = NULL; /* Release TX resources */ - dmaengine_terminate_all(dma->txchan); + dmaengine_terminate_sync(dma->txchan); dma_unmap_single(dma->txchan->device->dev, dma->tx_addr, UART_XMIT_SIZE, DMA_TO_DEVICE); dma_release_channel(dma->txchan); diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 5c0c123565ad..459d726f9d59 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -365,18 +365,19 @@ static int dw8250_probe(struct platform_device *pdev) struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); int irq = platform_get_irq(pdev, 0); struct uart_port *p = &uart.port; + struct device *dev = &pdev->dev; struct dw8250_data *data; int err; u32 val; if (!regs) { - dev_err(&pdev->dev, "no registers defined\n"); + dev_err(dev, "no registers defined\n"); return -EINVAL; } if (irq < 0) { if (irq != -EPROBE_DEFER) - dev_err(&pdev->dev, "cannot get irq\n"); + dev_err(dev, "cannot get irq\n"); return irq; } @@ -387,16 +388,16 @@ static int dw8250_probe(struct platform_device *pdev) p->pm = dw8250_do_pm; p->type = PORT_8250; p->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT; - p->dev = &pdev->dev; + p->dev = dev; p->iotype = UPIO_MEM; p->serial_in = dw8250_serial_in; p->serial_out = dw8250_serial_out; - p->membase = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); + p->membase = devm_ioremap(dev, regs->start, resource_size(regs)); if (!p->membase) return -ENOMEM; - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -404,57 +405,57 @@ static int dw8250_probe(struct platform_device *pdev) data->usr_reg = DW_UART_USR; p->private_data = data; - data->uart_16550_compatible = device_property_read_bool(p->dev, + data->uart_16550_compatible = device_property_read_bool(dev, "snps,uart-16550-compatible"); - err = device_property_read_u32(p->dev, "reg-shift", &val); + err = device_property_read_u32(dev, "reg-shift", &val); if (!err) p->regshift = val; - err = device_property_read_u32(p->dev, "reg-io-width", &val); + err = device_property_read_u32(dev, "reg-io-width", &val); if (!err && val == 4) { p->iotype = UPIO_MEM32; p->serial_in = dw8250_serial_in32; p->serial_out = dw8250_serial_out32; } - if (device_property_read_bool(p->dev, "dcd-override")) { + if (device_property_read_bool(dev, "dcd-override")) { /* Always report DCD as active */ data->msr_mask_on |= UART_MSR_DCD; data->msr_mask_off |= UART_MSR_DDCD; } - if (device_property_read_bool(p->dev, "dsr-override")) { + if (device_property_read_bool(dev, "dsr-override")) { /* Always report DSR as active */ data->msr_mask_on |= UART_MSR_DSR; data->msr_mask_off |= UART_MSR_DDSR; } - if (device_property_read_bool(p->dev, "cts-override")) { + if (device_property_read_bool(dev, "cts-override")) { /* Always report CTS as active */ data->msr_mask_on |= UART_MSR_CTS; data->msr_mask_off |= UART_MSR_DCTS; } - if (device_property_read_bool(p->dev, "ri-override")) { + if (device_property_read_bool(dev, "ri-override")) { /* Always report Ring indicator as inactive */ data->msr_mask_off |= UART_MSR_RI; data->msr_mask_off |= UART_MSR_TERI; } /* Always ask for fixed clock rate from a property. */ - device_property_read_u32(p->dev, "clock-frequency", &p->uartclk); + device_property_read_u32(dev, "clock-frequency", &p->uartclk); /* If there is separate baudclk, get the rate from it. */ - data->clk = devm_clk_get(&pdev->dev, "baudclk"); + data->clk = devm_clk_get(dev, "baudclk"); if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER) - data->clk = devm_clk_get(&pdev->dev, NULL); + data->clk = devm_clk_get(dev, NULL); if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) return -EPROBE_DEFER; if (!IS_ERR_OR_NULL(data->clk)) { err = clk_prepare_enable(data->clk); if (err) - dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n", + dev_warn(dev, "could not enable optional baudclk: %d\n", err); else p->uartclk = clk_get_rate(data->clk); @@ -462,24 +463,24 @@ static int dw8250_probe(struct platform_device *pdev) /* If no clock rate is defined, fail. */ if (!p->uartclk) { - dev_err(&pdev->dev, "clock rate not defined\n"); + dev_err(dev, "clock rate not defined\n"); return -EINVAL; } - data->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); - if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) { + data->pclk = devm_clk_get(dev, "apb_pclk"); + if (IS_ERR(data->pclk) && PTR_ERR(data->pclk) == -EPROBE_DEFER) { err = -EPROBE_DEFER; goto err_clk; } if (!IS_ERR(data->pclk)) { err = clk_prepare_enable(data->pclk); if (err) { - dev_err(&pdev->dev, "could not enable apb_pclk\n"); + dev_err(dev, "could not enable apb_pclk\n"); goto err_clk; } } - data->rst = devm_reset_control_get_optional(&pdev->dev, NULL); + data->rst = devm_reset_control_get_optional(dev, NULL); if (IS_ERR(data->rst) && PTR_ERR(data->rst) == -EPROBE_DEFER) { err = -EPROBE_DEFER; goto err_pclk; @@ -511,8 +512,8 @@ static int dw8250_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); return 0; @@ -624,6 +625,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = { { "APMC0D08", 0}, { "AMD0020", 0 }, { "AMDI0020", 0 }, + { "HISI0031", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c new file mode 100644 index 000000000000..886fcf37f291 --- /dev/null +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -0,0 +1,378 @@ +/* + * 8250_lpss.c - Driver for UART on Intel Braswell and various other Intel SoCs + * + * Copyright (C) 2016 Intel Corporation + * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/bitops.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/rational.h> + +#include <linux/dmaengine.h> +#include <linux/dma/dw.h> + +#include "8250.h" + +#define PCI_DEVICE_ID_INTEL_QRK_UARTx 0x0936 + +#define PCI_DEVICE_ID_INTEL_BYT_UART1 0x0f0a +#define PCI_DEVICE_ID_INTEL_BYT_UART2 0x0f0c + +#define PCI_DEVICE_ID_INTEL_BSW_UART1 0x228a +#define PCI_DEVICE_ID_INTEL_BSW_UART2 0x228c + +#define PCI_DEVICE_ID_INTEL_BDW_UART1 0x9ce3 +#define PCI_DEVICE_ID_INTEL_BDW_UART2 0x9ce4 + +/* Intel LPSS specific registers */ + +#define BYT_PRV_CLK 0x800 +#define BYT_PRV_CLK_EN BIT(0) +#define BYT_PRV_CLK_M_VAL_SHIFT 1 +#define BYT_PRV_CLK_N_VAL_SHIFT 16 +#define BYT_PRV_CLK_UPDATE BIT(31) + +#define BYT_TX_OVF_INT 0x820 +#define BYT_TX_OVF_INT_MASK BIT(1) + +struct lpss8250; + +struct lpss8250_board { + unsigned long freq; + unsigned int base_baud; + int (*setup)(struct lpss8250 *, struct uart_port *p); + void (*exit)(struct lpss8250 *); +}; + +struct lpss8250 { + int line; + struct lpss8250_board *board; + + /* DMA parameters */ + struct uart_8250_dma dma; + struct dw_dma_chip dma_chip; + struct dw_dma_slave dma_param; + u8 dma_maxburst; +}; + +static void byt_set_termios(struct uart_port *p, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud = tty_termios_baud_rate(termios); + struct lpss8250 *lpss = p->private_data; + unsigned long fref = lpss->board->freq, fuart = baud * 16; + unsigned long w = BIT(15) - 1; + unsigned long m, n; + u32 reg; + + /* Gracefully handle the B0 case: fall back to B9600 */ + fuart = fuart ? fuart : 9600 * 16; + + /* Get Fuart closer to Fref */ + fuart *= rounddown_pow_of_two(fref / fuart); + + /* + * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the + * dividers must be adjusted. + * + * uartclk = (m / n) * 100 MHz, where m <= n + */ + rational_best_approximation(fuart, fref, w, w, &m, &n); + p->uartclk = fuart; + + /* Reset the clock */ + reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT); + writel(reg, p->membase + BYT_PRV_CLK); + reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; + writel(reg, p->membase + BYT_PRV_CLK); + + p->status &= ~UPSTAT_AUTOCTS; + if (termios->c_cflag & CRTSCTS) + p->status |= UPSTAT_AUTOCTS; + + serial8250_do_set_termios(p, termios, old); +} + +static unsigned int byt_get_mctrl(struct uart_port *port) +{ + unsigned int ret = serial8250_do_get_mctrl(port); + + /* Force DCD and DSR signals to permanently be reported as active */ + ret |= TIOCM_CAR | TIOCM_DSR; + + return ret; +} + +static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) +{ + struct dw_dma_slave *param = &lpss->dma_param; + struct uart_8250_port *up = up_to_u8250p(port); + struct pci_dev *pdev = to_pci_dev(port->dev); + unsigned int dma_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); + struct pci_dev *dma_dev = pci_get_slot(pdev->bus, dma_devfn); + + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_BYT_UART1: + case PCI_DEVICE_ID_INTEL_BSW_UART1: + case PCI_DEVICE_ID_INTEL_BDW_UART1: + param->src_id = 3; + param->dst_id = 2; + break; + case PCI_DEVICE_ID_INTEL_BYT_UART2: + case PCI_DEVICE_ID_INTEL_BSW_UART2: + case PCI_DEVICE_ID_INTEL_BDW_UART2: + param->src_id = 5; + param->dst_id = 4; + break; + default: + return -EINVAL; + } + + param->dma_dev = &dma_dev->dev; + param->m_master = 0; + param->p_master = 1; + + /* TODO: Detect FIFO size automaticaly for DesignWare 8250 */ + port->fifosize = 64; + up->tx_loadsz = 64; + + lpss->dma_maxburst = 16; + + port->set_termios = byt_set_termios; + port->get_mctrl = byt_get_mctrl; + + /* Disable TX counter interrupts */ + writel(BYT_TX_OVF_INT_MASK, port->membase + BYT_TX_OVF_INT); + + return 0; +} + +#ifdef CONFIG_SERIAL_8250_DMA +static const struct dw_dma_platform_data qrk_serial_dma_pdata = { + .nr_channels = 2, + .is_private = true, + .is_nollp = true, + .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, + .chan_priority = CHAN_PRIORITY_ASCENDING, + .block_size = 4095, + .nr_masters = 1, + .data_width = {4}, +}; + +static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port) +{ + struct uart_8250_dma *dma = &lpss->dma; + struct dw_dma_chip *chip = &lpss->dma_chip; + struct dw_dma_slave *param = &lpss->dma_param; + struct pci_dev *pdev = to_pci_dev(port->dev); + int ret; + + chip->dev = &pdev->dev; + chip->irq = pdev->irq; + chip->regs = pci_ioremap_bar(pdev, 1); + chip->pdata = &qrk_serial_dma_pdata; + + /* Falling back to PIO mode if DMA probing fails */ + ret = dw_dma_probe(chip); + if (ret) + return; + + /* Special DMA address for UART */ + dma->rx_dma_addr = 0xfffff000; + dma->tx_dma_addr = 0xfffff000; + + param->dma_dev = &pdev->dev; + param->src_id = 0; + param->dst_id = 1; + param->hs_polarity = true; + + lpss->dma_maxburst = 8; +} + +static void qrk_serial_exit_dma(struct lpss8250 *lpss) +{ + struct dw_dma_slave *param = &lpss->dma_param; + + if (!param->dma_dev) + return; + dw_dma_remove(&lpss->dma_chip); +} +#else /* CONFIG_SERIAL_8250_DMA */ +static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port) {} +static void qrk_serial_exit_dma(struct lpss8250 *lpss) {} +#endif /* !CONFIG_SERIAL_8250_DMA */ + +static int qrk_serial_setup(struct lpss8250 *lpss, struct uart_port *port) +{ + struct pci_dev *pdev = to_pci_dev(port->dev); + int ret; + + ret = pci_alloc_irq_vectors(pdev, 1, 1, 0); + if (ret < 0) + return ret; + + port->irq = pci_irq_vector(pdev, 0); + + qrk_serial_setup_dma(lpss, port); + return 0; +} + +static void qrk_serial_exit(struct lpss8250 *lpss) +{ + qrk_serial_exit_dma(lpss); +} + +static bool lpss8250_dma_filter(struct dma_chan *chan, void *param) +{ + struct dw_dma_slave *dws = param; + + if (dws->dma_dev != chan->device->dev) + return false; + + chan->private = dws; + return true; +} + +static int lpss8250_dma_setup(struct lpss8250 *lpss, struct uart_8250_port *port) +{ + struct uart_8250_dma *dma = &lpss->dma; + struct dw_dma_slave *rx_param, *tx_param; + struct device *dev = port->port.dev; + + if (!lpss->dma_param.dma_dev) + return 0; + + rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL); + if (!rx_param) + return -ENOMEM; + + tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL); + if (!tx_param) + return -ENOMEM; + + *rx_param = lpss->dma_param; + dma->rxconf.src_maxburst = lpss->dma_maxburst; + + *tx_param = lpss->dma_param; + dma->txconf.dst_maxburst = lpss->dma_maxburst; + + dma->fn = lpss8250_dma_filter; + dma->rx_param = rx_param; + dma->tx_param = tx_param; + + port->dma = dma; + return 0; +} + +static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct uart_8250_port uart; + struct lpss8250 *lpss; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + pci_set_master(pdev); + + lpss = devm_kzalloc(&pdev->dev, sizeof(*lpss), GFP_KERNEL); + if (!lpss) + return -ENOMEM; + + lpss->board = (struct lpss8250_board *)id->driver_data; + + memset(&uart, 0, sizeof(struct uart_8250_port)); + + uart.port.dev = &pdev->dev; + uart.port.irq = pdev->irq; + uart.port.private_data = lpss; + uart.port.type = PORT_16550A; + uart.port.iotype = UPIO_MEM; + uart.port.regshift = 2; + uart.port.uartclk = lpss->board->base_baud * 16; + uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE; + uart.capabilities = UART_CAP_FIFO | UART_CAP_AFE; + uart.port.mapbase = pci_resource_start(pdev, 0); + uart.port.membase = pcim_iomap(pdev, 0, 0); + if (!uart.port.membase) + return -ENOMEM; + + ret = lpss->board->setup(lpss, &uart.port); + if (ret) + return ret; + + ret = lpss8250_dma_setup(lpss, &uart); + if (ret) + goto err_exit; + + ret = serial8250_register_8250_port(&uart); + if (ret < 0) + goto err_exit; + + lpss->line = ret; + + pci_set_drvdata(pdev, lpss); + return 0; + +err_exit: + if (lpss->board->exit) + lpss->board->exit(lpss); + return ret; +} + +static void lpss8250_remove(struct pci_dev *pdev) +{ + struct lpss8250 *lpss = pci_get_drvdata(pdev); + + if (lpss->board->exit) + lpss->board->exit(lpss); + + serial8250_unregister_port(lpss->line); +} + +static const struct lpss8250_board byt_board = { + .freq = 100000000, + .base_baud = 2764800, + .setup = byt_serial_setup, +}; + +static const struct lpss8250_board qrk_board = { + .freq = 44236800, + .base_baud = 2764800, + .setup = qrk_serial_setup, + .exit = qrk_serial_exit, +}; + +#define LPSS_DEVICE(id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board } + +static const struct pci_device_id pci_ids[] = { + LPSS_DEVICE(PCI_DEVICE_ID_INTEL_QRK_UARTx, qrk_board), + LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BYT_UART1, byt_board), + LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BYT_UART2, byt_board), + LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BSW_UART1, byt_board), + LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BSW_UART2, byt_board), + LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BDW_UART1, byt_board), + LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BDW_UART2, byt_board), + { }, +}; +MODULE_DEVICE_TABLE(pci, pci_ids); + +static struct pci_driver lpss8250_pci_driver = { + .name = "8250_lpss", + .id_table = pci_ids, + .probe = lpss8250_probe, + .remove = lpss8250_remove, +}; + +module_pci_driver(lpss8250_pci_driver); + +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel LPSS UART driver"); diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c index 20c5db2f4264..39c2324484dd 100644 --- a/drivers/tty/serial/8250/8250_mid.c +++ b/drivers/tty/serial/8250/8250_mid.c @@ -99,27 +99,27 @@ static int dnv_handle_irq(struct uart_port *p) struct uart_8250_port *up = up_to_u8250p(p); unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR); u32 status; - int ret = IRQ_NONE; + int ret = 0; int err; if (fisr & BIT(2)) { err = hsu_dma_get_status(&mid->dma_chip, 1, &status); if (err > 0) { serial8250_rx_dma_flush(up); - ret |= IRQ_HANDLED; + ret |= 1; } else if (err == 0) ret |= hsu_dma_do_irq(&mid->dma_chip, 1, status); } if (fisr & BIT(1)) { err = hsu_dma_get_status(&mid->dma_chip, 0, &status); if (err > 0) - ret |= IRQ_HANDLED; + ret |= 1; else if (err == 0) ret |= hsu_dma_do_irq(&mid->dma_chip, 0, status); } if (fisr & BIT(0)) ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR)); - return ret; + return IRQ_RETVAL(ret); } #define DNV_DMA_CHAN_OFFSET 0x80 diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index 3611ec9bb4fa..ce0cc471bfc3 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -62,7 +62,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, */ baud = uart_get_baud_rate(port, termios, old, port->uartclk / 16 / 0xffff, - port->uartclk / 16); + port->uartclk); if (baud <= 115200) { serial_port_out(port, UART_MTK_HIGHS, 0x0); @@ -76,10 +76,6 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, quot = DIV_ROUND_UP(port->uartclk, 4 * baud); } else { serial_port_out(port, UART_MTK_HIGHS, 0x3); - - /* Set to highest baudrate supported */ - if (baud >= 1152000) - baud = 921600; quot = DIV_ROUND_UP(port->uartclk, 256 * baud); } diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 38963d7bcf84..7a8b5fc81a19 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -195,6 +195,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev) switch (port_type) { case PORT_8250 ... PORT_MAX_8250: { + u32 tx_threshold; struct uart_8250_port port8250; memset(&port8250, 0, sizeof(port8250)); port8250.port = port; @@ -202,6 +203,12 @@ static int of_platform_serial_probe(struct platform_device *ofdev) if (port.fifosize) port8250.capabilities = UART_CAP_FIFO; + /* Check for TX FIFO threshold & set tx_loadsz */ + if ((of_property_read_u32(ofdev->dev.of_node, "tx-threshold", + &tx_threshold) == 0) && + (tx_threshold < port.fifosize)) + port8250.tx_loadsz = port.fifosize - tx_threshold; + if (of_property_read_bool(ofdev->dev.of_node, "auto-flow-control")) port8250.capabilities |= UART_CAP_AFE; diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index bc51b32b2774..b98c1578f45a 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -21,14 +21,10 @@ #include <linux/serial_core.h> #include <linux/8250_pci.h> #include <linux/bitops.h> -#include <linux/rational.h> #include <asm/byteorder.h> #include <asm/io.h> -#include <linux/dmaengine.h> -#include <linux/platform_data/dma-dw.h> - #include "8250.h" /* @@ -1349,160 +1345,6 @@ ce4100_serial_setup(struct serial_private *priv, return ret; } -#define PCI_DEVICE_ID_INTEL_BYT_UART1 0x0f0a -#define PCI_DEVICE_ID_INTEL_BYT_UART2 0x0f0c - -#define PCI_DEVICE_ID_INTEL_BSW_UART1 0x228a -#define PCI_DEVICE_ID_INTEL_BSW_UART2 0x228c - -#define PCI_DEVICE_ID_INTEL_BDW_UART1 0x9ce3 -#define PCI_DEVICE_ID_INTEL_BDW_UART2 0x9ce4 - -#define BYT_PRV_CLK 0x800 -#define BYT_PRV_CLK_EN (1 << 0) -#define BYT_PRV_CLK_M_VAL_SHIFT 1 -#define BYT_PRV_CLK_N_VAL_SHIFT 16 -#define BYT_PRV_CLK_UPDATE (1 << 31) - -#define BYT_TX_OVF_INT 0x820 -#define BYT_TX_OVF_INT_MASK (1 << 1) - -static void -byt_set_termios(struct uart_port *p, struct ktermios *termios, - struct ktermios *old) -{ - unsigned int baud = tty_termios_baud_rate(termios); - unsigned long fref = 100000000, fuart = baud * 16; - unsigned long w = BIT(15) - 1; - unsigned long m, n; - u32 reg; - - /* Gracefully handle the B0 case: fall back to B9600 */ - fuart = fuart ? fuart : 9600 * 16; - - /* Get Fuart closer to Fref */ - fuart *= rounddown_pow_of_two(fref / fuart); - - /* - * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the - * dividers must be adjusted. - * - * uartclk = (m / n) * 100 MHz, where m <= n - */ - rational_best_approximation(fuart, fref, w, w, &m, &n); - p->uartclk = fuart; - - /* Reset the clock */ - reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT); - writel(reg, p->membase + BYT_PRV_CLK); - reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; - writel(reg, p->membase + BYT_PRV_CLK); - - p->status &= ~UPSTAT_AUTOCTS; - if (termios->c_cflag & CRTSCTS) - p->status |= UPSTAT_AUTOCTS; - - serial8250_do_set_termios(p, termios, old); -} - -static bool byt_dma_filter(struct dma_chan *chan, void *param) -{ - struct dw_dma_slave *dws = param; - - if (dws->dma_dev != chan->device->dev) - return false; - - chan->private = dws; - return true; -} - -static unsigned int -byt_get_mctrl(struct uart_port *port) -{ - unsigned int ret = serial8250_do_get_mctrl(port); - - /* Force DCD and DSR signals to permanently be reported as active. */ - ret |= TIOCM_CAR | TIOCM_DSR; - - return ret; -} - -static int -byt_serial_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - struct pci_dev *pdev = priv->dev; - struct device *dev = port->port.dev; - struct uart_8250_dma *dma; - struct dw_dma_slave *tx_param, *rx_param; - struct pci_dev *dma_dev; - int ret; - - dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); - if (!dma) - return -ENOMEM; - - tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL); - if (!tx_param) - return -ENOMEM; - - rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL); - if (!rx_param) - return -ENOMEM; - - switch (pdev->device) { - case PCI_DEVICE_ID_INTEL_BYT_UART1: - case PCI_DEVICE_ID_INTEL_BSW_UART1: - case PCI_DEVICE_ID_INTEL_BDW_UART1: - rx_param->src_id = 3; - tx_param->dst_id = 2; - break; - case PCI_DEVICE_ID_INTEL_BYT_UART2: - case PCI_DEVICE_ID_INTEL_BSW_UART2: - case PCI_DEVICE_ID_INTEL_BDW_UART2: - rx_param->src_id = 5; - tx_param->dst_id = 4; - break; - default: - return -EINVAL; - } - - rx_param->m_master = 0; - rx_param->p_master = 1; - - dma->rxconf.src_maxburst = 16; - - tx_param->m_master = 0; - tx_param->p_master = 1; - - dma->txconf.dst_maxburst = 16; - - dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 0)); - rx_param->dma_dev = &dma_dev->dev; - tx_param->dma_dev = &dma_dev->dev; - - dma->fn = byt_dma_filter; - dma->rx_param = rx_param; - dma->tx_param = tx_param; - - ret = pci_default_setup(priv, board, port, idx); - port->port.iotype = UPIO_MEM; - port->port.type = PORT_16550A; - port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); - port->port.set_termios = byt_set_termios; - port->port.get_mctrl = byt_get_mctrl; - port->port.fifosize = 64; - port->tx_loadsz = 64; - port->dma = dma; - port->capabilities = UART_CAP_FIFO | UART_CAP_AFE; - - /* Disable Tx counter interrupts */ - writel(BYT_TX_OVF_INT_MASK, port->port.membase + BYT_TX_OVF_INT); - - return ret; -} - static int pci_omegapci_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1741,6 +1583,19 @@ static int pci_eg20t_init(struct pci_dev *dev) #define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358 #define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358 +#define UART_EXAR_MPIOINT_7_0 0x8f /* MPIOINT[7:0] */ +#define UART_EXAR_MPIOLVL_7_0 0x90 /* MPIOLVL[7:0] */ +#define UART_EXAR_MPIO3T_7_0 0x91 /* MPIO3T[7:0] */ +#define UART_EXAR_MPIOINV_7_0 0x92 /* MPIOINV[7:0] */ +#define UART_EXAR_MPIOSEL_7_0 0x93 /* MPIOSEL[7:0] */ +#define UART_EXAR_MPIOOD_7_0 0x94 /* MPIOOD[7:0] */ +#define UART_EXAR_MPIOINT_15_8 0x95 /* MPIOINT[15:8] */ +#define UART_EXAR_MPIOLVL_15_8 0x96 /* MPIOLVL[15:8] */ +#define UART_EXAR_MPIO3T_15_8 0x97 /* MPIO3T[15:8] */ +#define UART_EXAR_MPIOINV_15_8 0x98 /* MPIOINV[15:8] */ +#define UART_EXAR_MPIOSEL_15_8 0x99 /* MPIOSEL[15:8] */ +#define UART_EXAR_MPIOOD_15_8 0x9a /* MPIOOD[15:8] */ + static int pci_xr17c154_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1783,18 +1638,18 @@ pci_xr17v35x_setup(struct serial_private *priv, * Setup Multipurpose Input/Output pins. */ if (idx == 0) { - writeb(0x00, p + 0x8f); /*MPIOINT[7:0]*/ - writeb(0x00, p + 0x90); /*MPIOLVL[7:0]*/ - writeb(0x00, p + 0x91); /*MPIO3T[7:0]*/ - writeb(0x00, p + 0x92); /*MPIOINV[7:0]*/ - writeb(0x00, p + 0x93); /*MPIOSEL[7:0]*/ - writeb(0x00, p + 0x94); /*MPIOOD[7:0]*/ - writeb(0x00, p + 0x95); /*MPIOINT[15:8]*/ - writeb(0x00, p + 0x96); /*MPIOLVL[15:8]*/ - writeb(0x00, p + 0x97); /*MPIO3T[15:8]*/ - writeb(0x00, p + 0x98); /*MPIOINV[15:8]*/ - writeb(0x00, p + 0x99); /*MPIOSEL[15:8]*/ - writeb(0x00, p + 0x9a); /*MPIOOD[15:8]*/ + writeb(0x00, p + UART_EXAR_MPIOINT_7_0); + writeb(0x00, p + UART_EXAR_MPIOLVL_7_0); + writeb(0x00, p + UART_EXAR_MPIO3T_7_0); + writeb(0x00, p + UART_EXAR_MPIOINV_7_0); + writeb(0x00, p + UART_EXAR_MPIOSEL_7_0); + writeb(0x00, p + UART_EXAR_MPIOOD_7_0); + writeb(0x00, p + UART_EXAR_MPIOINT_15_8); + writeb(0x00, p + UART_EXAR_MPIOLVL_15_8); + writeb(0x00, p + UART_EXAR_MPIO3T_15_8); + writeb(0x00, p + UART_EXAR_MPIOINV_15_8); + writeb(0x00, p + UART_EXAR_MPIOSEL_15_8); + writeb(0x00, p + UART_EXAR_MPIOOD_15_8); } writeb(0x00, p + UART_EXAR_8XMODE); writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR); @@ -1830,20 +1685,20 @@ pci_fastcom335_setup(struct serial_private *priv, switch (priv->dev->device) { case PCI_DEVICE_ID_COMMTECH_4222PCI335: case PCI_DEVICE_ID_COMMTECH_4224PCI335: - writeb(0x78, p + 0x90); /* MPIOLVL[7:0] */ - writeb(0x00, p + 0x92); /* MPIOINV[7:0] */ - writeb(0x00, p + 0x93); /* MPIOSEL[7:0] */ + writeb(0x78, p + UART_EXAR_MPIOLVL_7_0); + writeb(0x00, p + UART_EXAR_MPIOINV_7_0); + writeb(0x00, p + UART_EXAR_MPIOSEL_7_0); break; case PCI_DEVICE_ID_COMMTECH_2324PCI335: case PCI_DEVICE_ID_COMMTECH_2328PCI335: - writeb(0x00, p + 0x90); /* MPIOLVL[7:0] */ - writeb(0xc0, p + 0x92); /* MPIOINV[7:0] */ - writeb(0xc0, p + 0x93); /* MPIOSEL[7:0] */ + writeb(0x00, p + UART_EXAR_MPIOLVL_7_0); + writeb(0xc0, p + UART_EXAR_MPIOINV_7_0); + writeb(0xc0, p + UART_EXAR_MPIOSEL_7_0); break; } - writeb(0x00, p + 0x8f); /* MPIOINT[7:0] */ - writeb(0x00, p + 0x91); /* MPIO3T[7:0] */ - writeb(0x00, p + 0x94); /* MPIOOD[7:0] */ + writeb(0x00, p + UART_EXAR_MPIOINT_7_0); + writeb(0x00, p + UART_EXAR_MPIO3T_7_0); + writeb(0x00, p + UART_EXAR_MPIOOD_7_0); } writeb(0x00, p + UART_EXAR_8XMODE); writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR); @@ -1934,7 +1789,6 @@ pci_wch_ch38x_setup(struct serial_private *priv, #define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022 #define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a #define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e -#define PCI_DEVICE_ID_INTEL_QRK_UART 0x0936 #define PCI_VENDOR_ID_SUNIX 0x1fd4 #define PCI_DEVICE_ID_SUNIX_1999 0x1999 @@ -2078,48 +1932,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = kt_serial_setup, }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BYT_UART1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = byt_serial_setup, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BYT_UART2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = byt_serial_setup, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BSW_UART1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = byt_serial_setup, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BSW_UART2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = byt_serial_setup, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BDW_UART1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = byt_serial_setup, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BDW_UART2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = byt_serial_setup, - }, /* * ITE */ @@ -2992,8 +2804,6 @@ enum pci_board_num_t { pbn_ADDIDATA_PCIe_4_3906250, pbn_ADDIDATA_PCIe_8_3906250, pbn_ce4100_1_115200, - pbn_byt, - pbn_qrk, pbn_omegapci, pbn_NETMOS9900_2s_115200, pbn_brcm_trumanage, @@ -3769,18 +3579,6 @@ static struct pciserial_board pci_boards[] = { .base_baud = 921600, .reg_shift = 2, }, - [pbn_byt] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 2764800, - .reg_shift = 2, - }, - [pbn_qrk] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 2764800, - .reg_shift = 2, - }, [pbn_omegapci] = { .flags = FL_BASE0, .num_ports = 8, @@ -3892,6 +3690,15 @@ static const struct pci_device_id blacklist[] = { { PCI_VDEVICE(INTEL, 0x081d), }, { PCI_VDEVICE(INTEL, 0x1191), }, { PCI_VDEVICE(INTEL, 0x19d8), }, + + /* Intel platforms with DesignWare UART */ + { PCI_VDEVICE(INTEL, 0x0936), }, + { PCI_VDEVICE(INTEL, 0x0f0a), }, + { PCI_VDEVICE(INTEL, 0x0f0c), }, + { PCI_VDEVICE(INTEL, 0x228a), }, + { PCI_VDEVICE(INTEL, 0x228c), }, + { PCI_VDEVICE(INTEL, 0x9ce3), }, + { PCI_VDEVICE(INTEL, 0x9ce4), }, }; /* @@ -5659,41 +5466,8 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_ce4100_1_115200 }, - /* Intel BayTrail */ - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART1, - PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, - pbn_byt }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART2, - PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, - pbn_byt }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW_UART1, - PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, - pbn_byt }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW_UART2, - PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, - pbn_byt }, - - /* Intel Broadwell */ - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_UART1, - PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, - pbn_byt }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_UART2, - PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, - pbn_byt }, /* - * Intel Quark x1000 - */ - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_UART, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_qrk }, - /* * Cronyx Omega PCI */ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_CRONYX_OMEGA, diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index bdfa659b9606..1bfb6fdbaa20 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -178,7 +178,7 @@ static const struct serial8250_config uart_config[] = { .fifo_size = 16, .tx_loadsz = 16, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, - .flags = UART_CAP_FIFO | UART_CAP_AFE, + .flags = UART_CAP_FIFO /* | UART_CAP_AFE */, }, [PORT_U6_16550A] = { .name = "U6_16550A", @@ -585,11 +585,11 @@ EXPORT_SYMBOL_GPL(serial8250_rpm_put); */ int serial8250_em485_init(struct uart_8250_port *p) { - if (p->em485 != NULL) + if (p->em485) return 0; p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC); - if (p->em485 == NULL) + if (!p->em485) return -ENOMEM; setup_timer(&p->em485->stop_tx_timer, @@ -619,7 +619,7 @@ EXPORT_SYMBOL_GPL(serial8250_em485_init); */ void serial8250_em485_destroy(struct uart_8250_port *p) { - if (p->em485 == NULL) + if (!p->em485) return; del_timer(&p->em485->start_tx_timer); @@ -1402,10 +1402,8 @@ static void serial8250_stop_rx(struct uart_port *port) static void __do_stop_tx_rs485(struct uart_8250_port *p) { - if (!p->em485) - return; - serial8250_em485_rts_after_send(p); + /* * Empty the RX FIFO, we are not interested in anything * received during the half-duplex transmission. @@ -1414,12 +1412,8 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p) if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) { serial8250_clear_fifos(p); - serial8250_rpm_get(p); - p->ier |= UART_IER_RLSI | UART_IER_RDI; serial_port_out(&p->port, UART_IER, p->ier); - - serial8250_rpm_put(p); } } @@ -1429,6 +1423,7 @@ static void serial8250_em485_handle_stop_tx(unsigned long arg) struct uart_8250_em485 *em485 = p->em485; unsigned long flags; + serial8250_rpm_get(p); spin_lock_irqsave(&p->port.lock, flags); if (em485 && em485->active_timer == &em485->stop_tx_timer) { @@ -1436,15 +1431,13 @@ static void serial8250_em485_handle_stop_tx(unsigned long arg) em485->active_timer = NULL; } spin_unlock_irqrestore(&p->port.lock, flags); + serial8250_rpm_put(p); } static void __stop_tx_rs485(struct uart_8250_port *p) { struct uart_8250_em485 *em485 = p->em485; - if (!em485) - return; - /* * __do_stop_tx_rs485 is going to set RTS according to config * AND flush RX FIFO if required. @@ -1475,7 +1468,7 @@ static inline void __stop_tx(struct uart_8250_port *p) unsigned char lsr = serial_in(p, UART_LSR); /* * To provide required timeing and allow FIFO transfer, - * __stop_tx_rs485 must be called only when both FIFO and + * __stop_tx_rs485() must be called only when both FIFO and * shift register are empty. It is for device driver to enable * interrupt on TEMT. */ @@ -1484,9 +1477,10 @@ static inline void __stop_tx(struct uart_8250_port *p) del_timer(&em485->start_tx_timer); em485->active_timer = NULL; + + __stop_tx_rs485(p); } __do_stop_tx(p); - __stop_tx_rs485(p); } static void serial8250_stop_tx(struct uart_port *port) @@ -1876,6 +1870,30 @@ static int exar_handle_irq(struct uart_port *port) return ret; } +/* + * Newer 16550 compatible parts such as the SC16C650 & Altera 16550 Soft IP + * have a programmable TX threshold that triggers the THRE interrupt in + * the IIR register. In this case, the THRE interrupt indicates the FIFO + * has space available. Load it up with tx_loadsz bytes. + */ +static int serial8250_tx_threshold_handle_irq(struct uart_port *port) +{ + unsigned long flags; + unsigned int iir = serial_port_in(port, UART_IIR); + + /* TX Threshold IRQ triggered so load up FIFO */ + if ((iir & UART_IIR_ID) == UART_IIR_THRI) { + struct uart_8250_port *up = up_to_u8250p(port); + + spin_lock_irqsave(&port->lock, flags); + serial8250_tx_chars(up); + spin_unlock_irqrestore(&port->lock, flags); + } + + iir = serial_port_in(port, UART_IIR); + return serial8250_handle_irq(port, iir); +} + static unsigned int serial8250_tx_empty(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); @@ -1988,6 +2006,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) if (--tmout == 0) break; udelay(1); + touch_nmi_watchdog(); } /* Wait up to 1s for flow control if necessary */ @@ -2164,6 +2183,25 @@ int serial8250_do_startup(struct uart_port *port) serial_port_out(port, UART_LCR, 0); } + /* + * For the Altera 16550 variants, set TX threshold trigger level. + */ + if (((port->type == PORT_ALTR_16550_F32) || + (port->type == PORT_ALTR_16550_F64) || + (port->type == PORT_ALTR_16550_F128)) && (port->fifosize > 1)) { + /* Bounds checking of TX threshold (valid 0 to fifosize-2) */ + if ((up->tx_loadsz < 2) || (up->tx_loadsz > port->fifosize)) { + pr_err("ttyS%d TX FIFO Threshold errors, skipping\n", + serial_index(port)); + } else { + serial_port_out(port, UART_ALTR_AFR, + UART_ALTR_EN_TXFIFO_LW); + serial_port_out(port, UART_ALTR_TX_LOW, + port->fifosize - up->tx_loadsz); + port->handle_irq = serial8250_tx_threshold_handle_irq; + } + } + if (port->irq) { unsigned char iir1; /* @@ -2499,8 +2537,6 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - unsigned int tolerance = port->uartclk / 100; - /* * Ask the core to calculate the divisor for us. * Allow 1% tolerance at the upper limit so uart clks marginally @@ -2509,7 +2545,7 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, */ return uart_get_baud_rate(port, termios, old, port->uartclk / 16 / 0xffff, - (port->uartclk + tolerance) / 16); + port->uartclk); } void @@ -2546,12 +2582,9 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, /* * MCR-based auto flow control. When AFE is enabled, RTS will be * deasserted when the receive FIFO contains more characters than - * the trigger, or the MCR RTS bit is cleared. In the case where - * the remote UART is not using CTS auto flow control, we must - * have sufficient FIFO entries for the latency of the remote - * UART to respond. IOW, at least 32 bytes of FIFO. + * the trigger, or the MCR RTS bit is cleared. */ - if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { + if (up->capabilities & UART_CAP_AFE) { up->mcr &= ~UART_MCR_AFE; if (termios->c_cflag & CRTSCTS) up->mcr |= UART_MCR_AFE; diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 7c6f7afca5dd..899834776b36 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -120,7 +120,6 @@ config SERIAL_8250_PCI tristate "8250/16550 PCI device support" if EXPERT depends on SERIAL_8250 && PCI default SERIAL_8250 - select RATIONAL help This builds standard PCI serial support. You may be able to disable this feature if you only need legacy serial support. @@ -402,6 +401,21 @@ config SERIAL_8250_INGENIC If you have a system using an Ingenic SoC and wish to make use of its UARTs, say Y to this option. If unsure, say N. +config SERIAL_8250_LPSS + tristate "Support for serial ports on Intel LPSS platforms" if EXPERT + default SERIAL_8250 + depends on SERIAL_8250 && PCI + depends on X86 || COMPILE_TEST + select DW_DMAC_CORE if SERIAL_8250_DMA + select DW_DMAC_PCI if (SERIAL_8250_DMA && X86_INTEL_LPSS) + select RATIONAL + help + Selecting this option will enable handling of the extra features + present on the UART found on various Intel platforms such as: + - Intel Baytrail SoC + - Intel Braswell SoC + - Intel Quark X1000 SoC + config SERIAL_8250_MID tristate "Support for serial ports on Intel MID platforms" if EXPERT default SERIAL_8250 diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index 367d403d28d5..276c6fb60337 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o +obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o obj-$(CONFIG_SERIAL_8250_MOXA) += 8250_moxa.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index 32df2a0cb060..e409d7dac7ab 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -280,7 +280,7 @@ static int altera_jtaguart_verify_port(struct uart_port *port, /* * Define the basic serial functions we support. */ -static struct uart_ops altera_jtaguart_ops = { +static const struct uart_ops altera_jtaguart_ops = { .tx_empty = altera_jtaguart_tx_empty, .get_mctrl = altera_jtaguart_get_mctrl, .set_mctrl = altera_jtaguart_set_mctrl, diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 61b607f2488e..820a74208696 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -404,7 +404,7 @@ static void altera_uart_poll_put_char(struct uart_port *port, unsigned char c) /* * Define the basic serial functions we support. */ -static struct uart_ops altera_uart_ops = { +static const struct uart_ops altera_uart_ops = { .tx_empty = altera_uart_tx_empty, .get_mctrl = altera_uart_get_mctrl, .set_mctrl = altera_uart_set_mctrl, diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8a9e213387a7..e2c33b9528d8 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -93,6 +93,10 @@ static u16 pl011_std_offsets[REG_ARRAY_SIZE] = { struct vendor_data { const u16 *reg_offset; unsigned int ifls; + unsigned int fr_busy; + unsigned int fr_dsr; + unsigned int fr_cts; + unsigned int fr_ri; bool access_32b; bool oversampling; bool dma_threshold; @@ -111,6 +115,10 @@ static unsigned int get_fifosize_arm(struct amba_device *dev) static struct vendor_data vendor_arm = { .reg_offset = pl011_std_offsets, .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, + .fr_busy = UART01x_FR_BUSY, + .fr_dsr = UART01x_FR_DSR, + .fr_cts = UART01x_FR_CTS, + .fr_ri = UART011_FR_RI, .oversampling = false, .dma_threshold = false, .cts_event_workaround = false, @@ -121,6 +129,10 @@ static struct vendor_data vendor_arm = { static struct vendor_data vendor_sbsa = { .reg_offset = pl011_std_offsets, + .fr_busy = UART01x_FR_BUSY, + .fr_dsr = UART01x_FR_DSR, + .fr_cts = UART01x_FR_CTS, + .fr_ri = UART011_FR_RI, .access_32b = true, .oversampling = false, .dma_threshold = false, @@ -164,6 +176,10 @@ static unsigned int get_fifosize_st(struct amba_device *dev) static struct vendor_data vendor_st = { .reg_offset = pl011_st_offsets, .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, + .fr_busy = UART01x_FR_BUSY, + .fr_dsr = UART01x_FR_DSR, + .fr_cts = UART01x_FR_CTS, + .fr_ri = UART011_FR_RI, .oversampling = true, .dma_threshold = true, .cts_event_workaround = true, @@ -188,11 +204,20 @@ static const u16 pl011_zte_offsets[REG_ARRAY_SIZE] = { [REG_DMACR] = ZX_UART011_DMACR, }; -static struct vendor_data vendor_zte __maybe_unused = { +static unsigned int get_fifosize_zte(struct amba_device *dev) +{ + return 16; +} + +static struct vendor_data vendor_zte = { .reg_offset = pl011_zte_offsets, .access_32b = true, .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, - .get_fifosize = get_fifosize_arm, + .fr_busy = ZX_UART01x_FR_BUSY, + .fr_dsr = ZX_UART01x_FR_DSR, + .fr_cts = ZX_UART01x_FR_CTS, + .fr_ri = ZX_UART011_FR_RI, + .get_fifosize = get_fifosize_zte, }; /* Deals with DMA transactions */ @@ -1167,7 +1192,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap) return; /* Disable RX and TX DMA */ - while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY) + while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy) cpu_relax(); spin_lock_irq(&uap->port.lock); @@ -1416,11 +1441,12 @@ static void pl011_modem_status(struct uart_amba_port *uap) if (delta & UART01x_FR_DCD) uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD); - if (delta & UART01x_FR_DSR) + if (delta & uap->vendor->fr_dsr) uap->port.icount.dsr++; - if (delta & UART01x_FR_CTS) - uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); + if (delta & uap->vendor->fr_cts) + uart_handle_cts_change(&uap->port, + status & uap->vendor->fr_cts); wake_up_interruptible(&uap->port.state->port.delta_msr_wait); } @@ -1493,7 +1519,8 @@ static unsigned int pl011_tx_empty(struct uart_port *port) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); unsigned int status = pl011_read(uap, REG_FR); - return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; + return status & (uap->vendor->fr_busy | UART01x_FR_TXFF) ? + 0 : TIOCSER_TEMT; } static unsigned int pl011_get_mctrl(struct uart_port *port) @@ -1508,9 +1535,9 @@ static unsigned int pl011_get_mctrl(struct uart_port *port) result |= tiocmbit TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR); - TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR); - TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS); - TIOCMBIT(UART011_FR_RI, TIOCM_RNG); + TIOCMBIT(uap->vendor->fr_dsr, TIOCM_DSR); + TIOCMBIT(uap->vendor->fr_cts, TIOCM_CTS); + TIOCMBIT(uap->vendor->fr_ri, TIOCM_RNG); #undef TIOCMBIT return result; } @@ -2191,7 +2218,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) * Finally, wait for transmitter to become empty * and restore the TCR */ - while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY) + while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy) cpu_relax(); if (!uap->vendor->always_enabled) pl011_write(old_cr, uap, REG_CR); @@ -2555,7 +2582,8 @@ static int sbsa_uart_probe(struct platform_device *pdev) ret = platform_get_irq(pdev, 0); if (ret < 0) { - dev_err(&pdev->dev, "cannot obtain irq\n"); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "cannot obtain irq\n"); return ret; } uap->port.irq = ret; @@ -2622,6 +2650,11 @@ static struct amba_id pl011_ids[] = { .mask = 0x00ffffff, .data = &vendor_st, }, + { + .id = AMBA_LINUX_ID(0x00, 0x1, 0xffe), + .mask = 0x00ffffff, + .data = &vendor_zte, + }, { 0, 0 }, }; diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 3a1de5c87cb4..5ac06fcaa9c6 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -464,7 +464,7 @@ static int arc_serial_poll_getchar(struct uart_port *port) } #endif -static struct uart_ops arc_serial_pops = { +static const struct uart_ops arc_serial_pops = { .tx_empty = arc_serial_tx_empty, .set_mctrl = arc_serial_set_mctrl, .get_mctrl = arc_serial_get_mctrl, diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 2eaa18ddef61..fd8aa1f4ba78 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -166,6 +166,7 @@ struct atmel_uart_port { u32 rts_low; bool ms_irq_enabled; u32 rtor; /* address of receiver timeout register if it exists */ + bool has_frac_baudrate; bool has_hw_timer; struct timer_list uart_timer; @@ -1634,8 +1635,8 @@ static void atmel_init_property(struct atmel_uart_port *atmel_port, if (np) { /* DMA/PDC usage specification */ - if (of_get_property(np, "atmel,use-dma-rx", NULL)) { - if (of_get_property(np, "dmas", NULL)) { + if (of_property_read_bool(np, "atmel,use-dma-rx")) { + if (of_property_read_bool(np, "dmas")) { atmel_port->use_dma_rx = true; atmel_port->use_pdc_rx = false; } else { @@ -1647,8 +1648,8 @@ static void atmel_init_property(struct atmel_uart_port *atmel_port, atmel_port->use_pdc_rx = false; } - if (of_get_property(np, "atmel,use-dma-tx", NULL)) { - if (of_get_property(np, "dmas", NULL)) { + if (of_property_read_bool(np, "atmel,use-dma-tx")) { + if (of_property_read_bool(np, "dmas")) { atmel_port->use_dma_tx = true; atmel_port->use_pdc_tx = false; } else { @@ -1745,6 +1746,11 @@ static void atmel_get_ip_name(struct uart_port *port) dbgu_uart = 0x44424755; /* DBGU */ new_uart = 0x55415254; /* UART */ + /* + * Only USART devices from at91sam9260 SOC implement fractional + * baudrate. + */ + atmel_port->has_frac_baudrate = false; atmel_port->has_hw_timer = false; if (name == new_uart) { @@ -1753,6 +1759,7 @@ static void atmel_get_ip_name(struct uart_port *port) atmel_port->rtor = ATMEL_UA_RTOR; } else if (name == usart) { dev_dbg(port->dev, "Usart\n"); + atmel_port->has_frac_baudrate = true; atmel_port->has_hw_timer = true; atmel_port->rtor = ATMEL_US_RTOR; } else if (name == dbgu_uart) { @@ -1764,6 +1771,7 @@ static void atmel_get_ip_name(struct uart_port *port) case 0x302: case 0x10213: dev_dbg(port->dev, "This version is usart\n"); + atmel_port->has_frac_baudrate = true; atmel_port->has_hw_timer = true; atmel_port->rtor = ATMEL_US_RTOR; break; @@ -1929,6 +1937,9 @@ static void atmel_shutdown(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + /* Disable modem control lines interrupts */ + atmel_disable_ms(port); + /* Disable interrupts at device level */ atmel_uart_writel(port, ATMEL_US_IDR, -1); @@ -1979,8 +1990,6 @@ static void atmel_shutdown(struct uart_port *port) */ free_irq(port->irq, port); - atmel_port->ms_irq_enabled = false; - atmel_flush_buffer(port); } @@ -2025,8 +2034,9 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned long flags; - unsigned int old_mode, mode, imr, quot, baud; + unsigned int old_mode, mode, imr, quot, baud, div, cd, fp = 0; /* save the current mode register */ mode = old_mode = atmel_uart_readl(port, ATMEL_US_MR); @@ -2036,12 +2046,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, ATMEL_US_PAR | ATMEL_US_USMODE); baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - quot = uart_get_divisor(port, baud); - - if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */ - quot /= 8; - mode |= ATMEL_US_USCLKS_MCK_DIV8; - } /* byte size */ switch (termios->c_cflag & CSIZE) { @@ -2160,7 +2164,31 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, atmel_uart_writel(port, ATMEL_US_CR, rts_state); } - /* set the baud rate */ + /* + * Set the baud rate: + * Fractional baudrate allows to setup output frequency more + * accurately. This feature is enabled only when using normal mode. + * baudrate = selected clock / (8 * (2 - OVER) * (CD + FP / 8)) + * Currently, OVER is always set to 0 so we get + * baudrate = selected clock / (16 * (CD + FP / 8)) + * then + * 8 CD + FP = selected clock / (2 * baudrate) + */ + if (atmel_port->has_frac_baudrate && + (mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_NORMAL) { + div = DIV_ROUND_CLOSEST(port->uartclk, baud * 2); + cd = div >> 3; + fp = div & ATMEL_US_FP_MASK; + } else { + cd = uart_get_divisor(port, baud); + } + + if (cd > 65535) { /* BRGR is 16-bit, so switch to slower clock */ + cd /= 8; + mode |= ATMEL_US_USCLKS_MCK_DIV8; + } + quot = cd | fp << ATMEL_US_FP_OFFSET; + atmel_uart_writel(port, ATMEL_US_BRGR, quot); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); @@ -2292,7 +2320,7 @@ static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) } #endif -static struct uart_ops atmel_pops = { +static const struct uart_ops atmel_pops = { .tx_empty = atmel_tx_empty, .set_mctrl = atmel_set_mctrl, .get_mctrl = atmel_get_mctrl, diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 5108fab953aa..583c9a0c7ecc 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -631,7 +631,7 @@ static int bcm_uart_verify_port(struct uart_port *port, } /* serial core callbacks */ -static struct uart_ops bcm_uart_ops = { +static const struct uart_ops bcm_uart_ops = { .tx_empty = bcm_uart_tx_empty, .get_mctrl = bcm_uart_get_mctrl, .set_mctrl = bcm_uart_set_mctrl, diff --git a/drivers/tty/serial/earlycon-arm-semihost.c b/drivers/tty/serial/earlycon-arm-semihost.c index 383db10fbb49..6bbeb699777c 100644 --- a/drivers/tty/serial/earlycon-arm-semihost.c +++ b/drivers/tty/serial/earlycon-arm-semihost.c @@ -53,7 +53,8 @@ static void smh_write(struct console *con, const char *s, unsigned n) uart_console_write(&dev->port, s, n, smh_putc); } -int __init early_smh_setup(struct earlycon_device *device, const char *opt) +static int +__init early_smh_setup(struct earlycon_device *device, const char *opt) { device->con->write = smh_write; return 0; diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 067783f0523c..c3651540e1ba 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -21,6 +21,7 @@ #include <linux/sizes.h> #include <linux/of.h> #include <linux/of_fdt.h> +#include <linux/acpi.h> #ifdef CONFIG_FIX_EARLYCON_MEM #include <asm/fixmap.h> @@ -38,7 +39,7 @@ static struct earlycon_device early_console_dev = { .con = &early_con, }; -static void __iomem * __init earlycon_map(unsigned long paddr, size_t size) +static void __iomem * __init earlycon_map(resource_size_t paddr, size_t size) { void __iomem *base; #ifdef CONFIG_FIX_EARLYCON_MEM @@ -49,8 +50,7 @@ static void __iomem * __init earlycon_map(unsigned long paddr, size_t size) base = ioremap(paddr, size); #endif if (!base) - pr_err("%s: Couldn't map 0x%llx\n", __func__, - (unsigned long long)paddr); + pr_err("%s: Couldn't map %pa\n", __func__, &paddr); return base; } @@ -92,7 +92,7 @@ static int __init parse_options(struct earlycon_device *device, char *options) { struct uart_port *port = &device->port; int length; - unsigned long addr; + resource_size_t addr; if (uart_parse_earlycon(options, &port->iotype, &addr, &options)) return -EINVAL; @@ -199,6 +199,14 @@ int __init setup_earlycon(char *buf) return -ENOENT; } +/* + * When CONFIG_ACPI_SPCR_TABLE is defined, "earlycon" without parameters in + * command line does not start DT earlycon immediately, instead it defers + * starting it until DT/ACPI decision is made. At that time if ACPI is enabled + * call parse_spcr(), else call early_init_dt_scan_chosen_stdout() + */ +bool earlycon_init_is_deferred __initdata; + /* early_param wrapper for setup_earlycon() */ static int __init param_setup_earlycon(char *buf) { @@ -208,8 +216,14 @@ static int __init param_setup_earlycon(char *buf) * Just 'earlycon' is a valid param for devicetree earlycons; * don't generate a warning from parse_early_params() in that case */ - if (!buf || !buf[0]) - return 0; + if (!buf || !buf[0]) { + if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) { + earlycon_init_is_deferred = true; + return 0; + } else { + return early_init_dt_scan_chosen_stdout(); + } + } err = setup_earlycon(buf); if (err == -ENOENT || err == -EALREADY) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 7f95f782a485..de9d5107c00a 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -224,7 +224,8 @@ #define UARTWATER_TXWATER_OFF 0 #define UARTWATER_RXWATER_OFF 16 -#define FSL_UART_RX_DMA_BUFFER_SIZE 64 +/* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */ +#define DMA_RX_TIMEOUT (10) #define DRIVER_NAME "fsl-lpuart" #define DEV_NAME "ttyLP" @@ -243,18 +244,18 @@ struct lpuart_port { struct dma_chan *dma_rx_chan; struct dma_async_tx_descriptor *dma_tx_desc; struct dma_async_tx_descriptor *dma_rx_desc; - dma_addr_t dma_tx_buf_bus; - dma_addr_t dma_rx_buf_bus; dma_cookie_t dma_tx_cookie; dma_cookie_t dma_rx_cookie; - unsigned char *dma_tx_buf_virt; - unsigned char *dma_rx_buf_virt; unsigned int dma_tx_bytes; unsigned int dma_rx_bytes; - int dma_tx_in_progress; - int dma_rx_in_progress; + bool dma_tx_in_progress; unsigned int dma_rx_timeout; struct timer_list lpuart_timer; + struct scatterlist rx_sgl, tx_sgl[2]; + struct circ_buf rx_ring; + int rx_dma_rng_buf_len; + unsigned int dma_tx_nents; + wait_queue_head_t dma_wait; }; static const struct of_device_id lpuart_dt_ids[] = { @@ -270,7 +271,6 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids); /* Forward declare this for the dma callbacks*/ static void lpuart_dma_tx_complete(void *arg); -static void lpuart_dma_rx_complete(void *arg); static u32 lpuart32_read(void __iomem *addr) { @@ -316,141 +316,103 @@ static void lpuart32_stop_rx(struct uart_port *port) lpuart32_write(temp & ~UARTCTRL_RE, port->membase + UARTCTRL); } -static void lpuart_copy_rx_to_tty(struct lpuart_port *sport, - struct tty_port *tty, int count) +static void lpuart_dma_tx(struct lpuart_port *sport) { - int copied; - - sport->port.icount.rx += count; + struct circ_buf *xmit = &sport->port.state->xmit; + struct scatterlist *sgl = sport->tx_sgl; + struct device *dev = sport->port.dev; + int ret; - if (!tty) { - dev_err(sport->port.dev, "No tty port\n"); + if (sport->dma_tx_in_progress) return; - } - dma_sync_single_for_cpu(sport->port.dev, sport->dma_rx_buf_bus, - FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE); - copied = tty_insert_flip_string(tty, - ((unsigned char *)(sport->dma_rx_buf_virt)), count); + sport->dma_tx_bytes = uart_circ_chars_pending(xmit); - if (copied != count) { - WARN_ON(1); - dev_err(sport->port.dev, "RxData copy to tty layer failed\n"); + if (xmit->tail < xmit->head) { + sport->dma_tx_nents = 1; + sg_init_one(sgl, xmit->buf + xmit->tail, sport->dma_tx_bytes); + } else { + sport->dma_tx_nents = 2; + sg_init_table(sgl, 2); + sg_set_buf(sgl, xmit->buf + xmit->tail, + UART_XMIT_SIZE - xmit->tail); + sg_set_buf(sgl + 1, xmit->buf, xmit->head); } - dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus, - FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE); -} - -static void lpuart_pio_tx(struct lpuart_port *sport) -{ - struct circ_buf *xmit = &sport->port.state->xmit; - unsigned long flags; - - spin_lock_irqsave(&sport->port.lock, flags); - - while (!uart_circ_empty(xmit) && - readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size) { - writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - sport->port.icount.tx++; + ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); + if (!ret) { + dev_err(dev, "DMA mapping error for TX.\n"); + return; } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - - if (uart_circ_empty(xmit)) - writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS, - sport->port.membase + UARTCR5); - - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static int lpuart_dma_tx(struct lpuart_port *sport, unsigned long count) -{ - struct circ_buf *xmit = &sport->port.state->xmit; - dma_addr_t tx_bus_addr; - - dma_sync_single_for_device(sport->port.dev, sport->dma_tx_buf_bus, - UART_XMIT_SIZE, DMA_TO_DEVICE); - sport->dma_tx_bytes = count & ~(sport->txfifo_size - 1); - tx_bus_addr = sport->dma_tx_buf_bus + xmit->tail; - sport->dma_tx_desc = dmaengine_prep_slave_single(sport->dma_tx_chan, - tx_bus_addr, sport->dma_tx_bytes, + sport->dma_tx_desc = dmaengine_prep_slave_sg(sport->dma_tx_chan, sgl, + sport->dma_tx_nents, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); - if (!sport->dma_tx_desc) { - dev_err(sport->port.dev, "Not able to get desc for tx\n"); - return -EIO; + dma_unmap_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); + dev_err(dev, "Cannot prepare TX slave DMA!\n"); + return; } sport->dma_tx_desc->callback = lpuart_dma_tx_complete; sport->dma_tx_desc->callback_param = sport; - sport->dma_tx_in_progress = 1; + sport->dma_tx_in_progress = true; sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc); dma_async_issue_pending(sport->dma_tx_chan); - return 0; -} - -static void lpuart_prepare_tx(struct lpuart_port *sport) -{ - struct circ_buf *xmit = &sport->port.state->xmit; - unsigned long count = CIRC_CNT_TO_END(xmit->head, - xmit->tail, UART_XMIT_SIZE); - - if (!count) - return; - - if (count < sport->txfifo_size) - writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_TDMAS, - sport->port.membase + UARTCR5); - else { - writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS, - sport->port.membase + UARTCR5); - lpuart_dma_tx(sport, count); - } } static void lpuart_dma_tx_complete(void *arg) { struct lpuart_port *sport = arg; + struct scatterlist *sgl = &sport->tx_sgl[0]; struct circ_buf *xmit = &sport->port.state->xmit; unsigned long flags; - async_tx_ack(sport->dma_tx_desc); - spin_lock_irqsave(&sport->port.lock, flags); + dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); + xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1); - sport->dma_tx_in_progress = 0; + + sport->port.icount.tx += sport->dma_tx_bytes; + sport->dma_tx_in_progress = false; + spin_unlock_irqrestore(&sport->port.lock, flags); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); - lpuart_prepare_tx(sport); + if (waitqueue_active(&sport->dma_wait)) { + wake_up(&sport->dma_wait); + return; + } + + spin_lock_irqsave(&sport->port.lock, flags); + + if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port)) + lpuart_dma_tx(sport); spin_unlock_irqrestore(&sport->port.lock, flags); } -static int lpuart_dma_rx(struct lpuart_port *sport) +static int lpuart_dma_tx_request(struct uart_port *port) { - dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus, - FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE); - sport->dma_rx_desc = dmaengine_prep_slave_single(sport->dma_rx_chan, - sport->dma_rx_buf_bus, FSL_UART_RX_DMA_BUFFER_SIZE, - DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + struct dma_slave_config dma_tx_sconfig = {}; + int ret; - if (!sport->dma_rx_desc) { - dev_err(sport->port.dev, "Not able to get desc for rx\n"); - return -EIO; - } + dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR; + 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; + ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig); - sport->dma_rx_desc->callback = lpuart_dma_rx_complete; - sport->dma_rx_desc->callback_param = sport; - sport->dma_rx_in_progress = 1; - sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc); - dma_async_issue_pending(sport->dma_rx_chan); + if (ret) { + dev_err(sport->port.dev, + "DMA slave config failed, err = %d\n", ret); + return ret; + } return 0; } @@ -458,75 +420,17 @@ static int lpuart_dma_rx(struct lpuart_port *sport) static void lpuart_flush_buffer(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + if (sport->lpuart_dma_tx_use) { + if (sport->dma_tx_in_progress) { + dma_unmap_sg(sport->port.dev, &sport->tx_sgl[0], + sport->dma_tx_nents, DMA_TO_DEVICE); + sport->dma_tx_in_progress = false; + } dmaengine_terminate_all(sport->dma_tx_chan); - sport->dma_tx_in_progress = 0; } } -static void lpuart_dma_rx_complete(void *arg) -{ - struct lpuart_port *sport = arg; - struct tty_port *port = &sport->port.state->port; - unsigned long flags; - - async_tx_ack(sport->dma_rx_desc); - mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout); - - spin_lock_irqsave(&sport->port.lock, flags); - - sport->dma_rx_in_progress = 0; - lpuart_copy_rx_to_tty(sport, port, FSL_UART_RX_DMA_BUFFER_SIZE); - tty_flip_buffer_push(port); - lpuart_dma_rx(sport); - - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static void lpuart_timer_func(unsigned long data) -{ - struct lpuart_port *sport = (struct lpuart_port *)data; - struct tty_port *port = &sport->port.state->port; - struct dma_tx_state state; - unsigned long flags; - unsigned char temp; - int count; - - del_timer(&sport->lpuart_timer); - dmaengine_pause(sport->dma_rx_chan); - dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state); - dmaengine_terminate_all(sport->dma_rx_chan); - count = FSL_UART_RX_DMA_BUFFER_SIZE - state.residue; - async_tx_ack(sport->dma_rx_desc); - - spin_lock_irqsave(&sport->port.lock, flags); - - sport->dma_rx_in_progress = 0; - lpuart_copy_rx_to_tty(sport, port, count); - tty_flip_buffer_push(port); - temp = readb(sport->port.membase + UARTCR5); - writeb(temp & ~UARTCR5_RDMAS, sport->port.membase + UARTCR5); - - spin_unlock_irqrestore(&sport->port.lock, flags); -} - -static inline void lpuart_prepare_rx(struct lpuart_port *sport) -{ - unsigned long flags; - unsigned char temp; - - spin_lock_irqsave(&sport->port.lock, flags); - - sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout; - add_timer(&sport->lpuart_timer); - - lpuart_dma_rx(sport); - temp = readb(sport->port.membase + UARTCR5); - writeb(temp | UARTCR5_RDMAS, sport->port.membase + UARTCR5); - - spin_unlock_irqrestore(&sport->port.lock, flags); -} - static inline void lpuart_transmit_buffer(struct lpuart_port *sport) { struct circ_buf *xmit = &sport->port.state->xmit; @@ -580,8 +484,8 @@ static void lpuart_start_tx(struct uart_port *port) writeb(temp | UARTCR2_TIE, port->membase + UARTCR2); if (sport->lpuart_dma_tx_use) { - if (!uart_circ_empty(xmit) && !sport->dma_tx_in_progress) - lpuart_prepare_tx(sport); + if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) + lpuart_dma_tx(sport); } else { if (readb(port->membase + UARTSR1) & UARTSR1_TDRE) lpuart_transmit_buffer(sport); @@ -600,6 +504,29 @@ static void lpuart32_start_tx(struct uart_port *port) lpuart32_transmit_buffer(sport); } +/* return TIOCSER_TEMT when transmitter is not busy */ +static unsigned int lpuart_tx_empty(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + unsigned char sr1 = readb(port->membase + UARTSR1); + unsigned char sfifo = readb(port->membase + UARTSFIFO); + + if (sport->dma_tx_in_progress) + return 0; + + if (sr1 & UARTSR1_TC && sfifo & UARTSFIFO_TXEMPT) + return TIOCSER_TEMT; + + return 0; +} + +static unsigned int lpuart32_tx_empty(struct uart_port *port) +{ + return (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TC) ? + TIOCSER_TEMT : 0; +} + static irqreturn_t lpuart_txint(int irq, void *dev_id) { struct lpuart_port *sport = dev_id; @@ -766,23 +693,15 @@ out: static irqreturn_t lpuart_int(int irq, void *dev_id) { struct lpuart_port *sport = dev_id; - unsigned char sts, crdma; + unsigned char sts; sts = readb(sport->port.membase + UARTSR1); - crdma = readb(sport->port.membase + UARTCR5); - if (sts & UARTSR1_RDRF && !(crdma & UARTCR5_RDMAS)) { - if (sport->lpuart_dma_rx_use) - lpuart_prepare_rx(sport); - else - lpuart_rxint(irq, dev_id); - } - if (sts & UARTSR1_TDRE && !(crdma & UARTCR5_TDMAS)) { - if (sport->lpuart_dma_tx_use) - lpuart_pio_tx(sport); - else - lpuart_txint(irq, dev_id); - } + if (sts & UARTSR1_RDRF) + lpuart_rxint(irq, dev_id); + + if (sts & UARTSR1_TDRE) + lpuart_txint(irq, dev_id); return IRQ_HANDLED; } @@ -807,17 +726,241 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id) return IRQ_HANDLED; } -/* return TIOCSER_TEMT when transmitter is not busy */ -static unsigned int lpuart_tx_empty(struct uart_port *port) +static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) { - return (readb(port->membase + UARTSR1) & UARTSR1_TC) ? - TIOCSER_TEMT : 0; + struct tty_port *port = &sport->port.state->port; + struct dma_tx_state state; + enum dma_status dmastat; + struct circ_buf *ring = &sport->rx_ring; + unsigned long flags; + int count = 0; + unsigned char sr; + + sr = readb(sport->port.membase + UARTSR1); + + 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); + + spin_lock_irqsave(&sport->port.lock, flags); + + dmastat = dmaengine_tx_status(sport->dma_rx_chan, + sport->dma_rx_cookie, + &state); + + if (dmastat == DMA_ERROR) { + dev_err(sport->port.dev, "Rx DMA transfer failed!\n"); + spin_unlock_irqrestore(&sport->port.lock, flags); + return; + } + + /* CPU claims ownership of RX DMA buffer */ + dma_sync_sg_for_cpu(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); + + /* + * ring->head points to the end of data already written by the DMA. + * ring->tail points to the beginning of data to be read by the + * framework. + * The current transfer size should not be larger than the dma buffer + * length. + */ + ring->head = sport->rx_sgl.length - state.residue; + BUG_ON(ring->head > sport->rx_sgl.length); + /* + * At this point ring->head may point to the first byte right after the + * last byte of the dma buffer: + * 0 <= ring->head <= sport->rx_sgl.length + * + * However ring->tail must always points inside the dma buffer: + * 0 <= ring->tail <= sport->rx_sgl.length - 1 + * + * Since we use a ring buffer, we have to handle the case + * where head is lower than tail. In such a case, we first read from + * tail to the end of the buffer then reset tail. + */ + if (ring->head < ring->tail) { + count = sport->rx_sgl.length - ring->tail; + + tty_insert_flip_string(port, ring->buf + ring->tail, count); + ring->tail = 0; + sport->port.icount.rx += count; + } + + /* Finally we read data from tail to head */ + if (ring->tail < ring->head) { + count = ring->head - ring->tail; + tty_insert_flip_string(port, ring->buf + ring->tail, count); + /* Wrap ring->head if needed */ + if (ring->head >= sport->rx_sgl.length) + ring->head = 0; + ring->tail = ring->head; + sport->port.icount.rx += count; + } + + dma_sync_sg_for_device(sport->port.dev, &sport->rx_sgl, 1, + DMA_FROM_DEVICE); + + spin_unlock_irqrestore(&sport->port.lock, flags); + + tty_flip_buffer_push(port); + mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout); } -static unsigned int lpuart32_tx_empty(struct uart_port *port) +static void lpuart_dma_rx_complete(void *arg) { - return (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TC) ? - TIOCSER_TEMT : 0; + struct lpuart_port *sport = arg; + + lpuart_copy_rx_to_tty(sport); +} + +static void lpuart_timer_func(unsigned long data) +{ + struct lpuart_port *sport = (struct lpuart_port *)data; + + lpuart_copy_rx_to_tty(sport); +} + +static inline int lpuart_start_rx_dma(struct lpuart_port *sport) +{ + struct dma_slave_config dma_rx_sconfig = {}; + struct circ_buf *ring = &sport->rx_ring; + int ret, nent; + int bits, baud; + struct tty_struct *tty = tty_port_tty_get(&sport->port.state->port); + struct ktermios *termios = &tty->termios; + + baud = tty_get_baud_rate(tty); + + bits = (termios->c_cflag & CSIZE) == CS7 ? 9 : 10; + if (termios->c_cflag & PARENB) + bits++; + + /* + * Calculate length of one DMA buffer size to keep latency below + * 10ms at any baud rate. + */ + sport->rx_dma_rng_buf_len = (DMA_RX_TIMEOUT * baud / bits / 1000) * 2; + sport->rx_dma_rng_buf_len = (1 << (fls(sport->rx_dma_rng_buf_len) - 1)); + if (sport->rx_dma_rng_buf_len < 16) + sport->rx_dma_rng_buf_len = 16; + + ring->buf = kmalloc(sport->rx_dma_rng_buf_len, GFP_ATOMIC); + if (!ring->buf) { + dev_err(sport->port.dev, "Ring buf alloc failed\n"); + return -ENOMEM; + } + + sg_init_one(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len); + sg_set_buf(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len); + nent = dma_map_sg(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); + + if (!nent) { + dev_err(sport->port.dev, "DMA Rx mapping error\n"); + return -EINVAL; + } + + dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR; + 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; + ret = dmaengine_slave_config(sport->dma_rx_chan, &dma_rx_sconfig); + + if (ret < 0) { + dev_err(sport->port.dev, + "DMA Rx slave config failed, err = %d\n", ret); + return ret; + } + + sport->dma_rx_desc = dmaengine_prep_dma_cyclic(sport->dma_rx_chan, + sg_dma_address(&sport->rx_sgl), + sport->rx_sgl.length, + sport->rx_sgl.length / 2, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!sport->dma_rx_desc) { + dev_err(sport->port.dev, "Cannot prepare cyclic DMA\n"); + return -EFAULT; + } + + sport->dma_rx_desc->callback = lpuart_dma_rx_complete; + sport->dma_rx_desc->callback_param = 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); + + return 0; +} + +static void lpuart_dma_rx_free(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + + if (sport->dma_rx_chan) + dmaengine_terminate_all(sport->dma_rx_chan); + + dma_unmap_sg(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); + kfree(sport->rx_ring.buf); + sport->rx_ring.tail = 0; + sport->rx_ring.head = 0; + sport->dma_rx_desc = NULL; + sport->dma_rx_cookie = -EINVAL; +} + +static int lpuart_config_rs485(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + + u8 modem = readb(sport->port.membase + UARTMODEM) & + ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); + writeb(modem, sport->port.membase + UARTMODEM); + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable auto RS-485 RTS mode */ + modem |= UARTMODEM_TXRTSE; + + /* + * RTS needs to be logic HIGH either during transer _or_ after + * transfer, other variants are not supported by the hardware. + */ + + if (!(rs485->flags & (SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND))) + rs485->flags |= SER_RS485_RTS_ON_SEND; + + if (rs485->flags & SER_RS485_RTS_ON_SEND && + rs485->flags & SER_RS485_RTS_AFTER_SEND) + rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + + /* + * The hardware defaults to RTS logic HIGH while transfer. + * Switch polarity in case RTS shall be logic HIGH + * after transfer. + * Note: UART is assumed to be active high. + */ + if (rs485->flags & SER_RS485_RTS_ON_SEND) + modem &= ~UARTMODEM_TXRTSPOL; + else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) + modem |= UARTMODEM_TXRTSPOL; + } + + /* Store the new configuration */ + sport->port.rs485 = *rs485; + + writeb(modem, sport->port.membase + UARTMODEM); + return 0; } static unsigned int lpuart_get_mctrl(struct uart_port *port) @@ -853,17 +996,22 @@ static unsigned int lpuart32_get_mctrl(struct uart_port *port) static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl) { unsigned char temp; + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); - temp = readb(port->membase + UARTMODEM) & + /* Make sure RXRTSE bit is not set when RS485 is enabled */ + if (!(sport->port.rs485.flags & SER_RS485_ENABLED)) { + temp = readb(sport->port.membase + UARTMODEM) & ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); - if (mctrl & TIOCM_RTS) - temp |= UARTMODEM_RXRTSE; + if (mctrl & TIOCM_RTS) + temp |= UARTMODEM_RXRTSE; - if (mctrl & TIOCM_CTS) - temp |= UARTMODEM_TXCTSE; + if (mctrl & TIOCM_CTS) + temp |= UARTMODEM_TXCTSE; - writeb(temp, port->membase + UARTMODEM); + writeb(temp, port->membase + UARTMODEM); + } } static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -921,13 +1069,16 @@ static void lpuart_setup_watermark(struct lpuart_port *sport) writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE, sport->port.membase + UARTPFIFO); - /* explicitly clear RDRF */ - readb(sport->port.membase + UARTSR1); - /* flush Tx and Rx FIFO */ writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH, sport->port.membase + UARTCFIFO); + /* explicitly clear RDRF */ + if (readb(sport->port.membase + UARTSR1) & UARTSR1_RDRF) { + readb(sport->port.membase + UARTDR); + writeb(UARTSFIFO_RXUF, sport->port.membase + UARTSFIFO); + } + writeb(0, sport->port.membase + UARTTWFIFO); writeb(1, sport->port.membase + UARTRWFIFO); @@ -960,110 +1111,12 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport) lpuart32_write(ctrl_saved, sport->port.membase + UARTCTRL); } -static int lpuart_dma_tx_request(struct uart_port *port) -{ - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); - struct dma_slave_config dma_tx_sconfig; - dma_addr_t dma_bus; - unsigned char *dma_buf; - int ret; - - dma_bus = dma_map_single(sport->dma_tx_chan->device->dev, - sport->port.state->xmit.buf, - UART_XMIT_SIZE, DMA_TO_DEVICE); - - if (dma_mapping_error(sport->dma_tx_chan->device->dev, dma_bus)) { - dev_err(sport->port.dev, "dma_map_single tx failed\n"); - return -ENOMEM; - } - - dma_buf = sport->port.state->xmit.buf; - dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR; - dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - dma_tx_sconfig.dst_maxburst = sport->txfifo_size; - dma_tx_sconfig.direction = DMA_MEM_TO_DEV; - ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig); - - if (ret < 0) { - dev_err(sport->port.dev, - "Dma slave config failed, err = %d\n", ret); - return ret; - } - - sport->dma_tx_buf_virt = dma_buf; - sport->dma_tx_buf_bus = dma_bus; - sport->dma_tx_in_progress = 0; - - return 0; -} - -static int lpuart_dma_rx_request(struct uart_port *port) +static void rx_dma_timer_init(struct lpuart_port *sport) { - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); - struct dma_slave_config dma_rx_sconfig; - dma_addr_t dma_bus; - unsigned char *dma_buf; - int ret; - - dma_buf = devm_kzalloc(sport->port.dev, - FSL_UART_RX_DMA_BUFFER_SIZE, GFP_KERNEL); - - if (!dma_buf) { - dev_err(sport->port.dev, "Dma rx alloc failed\n"); - return -ENOMEM; - } - - dma_bus = dma_map_single(sport->dma_rx_chan->device->dev, dma_buf, - FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE); - - if (dma_mapping_error(sport->dma_rx_chan->device->dev, dma_bus)) { - dev_err(sport->port.dev, "dma_map_single rx failed\n"); - return -ENOMEM; - } - - dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR; - 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; - ret = dmaengine_slave_config(sport->dma_rx_chan, &dma_rx_sconfig); - - if (ret < 0) { - dev_err(sport->port.dev, - "Dma slave config failed, err = %d\n", ret); - return ret; - } - - sport->dma_rx_buf_virt = dma_buf; - sport->dma_rx_buf_bus = dma_bus; - sport->dma_rx_in_progress = 0; - - return 0; -} - -static void lpuart_dma_tx_free(struct uart_port *port) -{ - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); - - dma_unmap_single(sport->port.dev, sport->dma_tx_buf_bus, - UART_XMIT_SIZE, DMA_TO_DEVICE); - - sport->dma_tx_buf_bus = 0; - sport->dma_tx_buf_virt = NULL; -} - -static void lpuart_dma_rx_free(struct uart_port *port) -{ - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); - - dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus, - FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE); - - sport->dma_rx_buf_bus = 0; - sport->dma_rx_buf_virt = NULL; + setup_timer(&sport->lpuart_timer, lpuart_timer_func, + (unsigned long)sport); + sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout; + add_timer(&sport->lpuart_timer); } static int lpuart_startup(struct uart_port *port) @@ -1084,22 +1137,6 @@ static int lpuart_startup(struct uart_port *port) sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) & UARTPFIFO_FIFOSIZE_MASK) + 1); - if (sport->dma_rx_chan && !lpuart_dma_rx_request(port)) { - sport->lpuart_dma_rx_use = true; - setup_timer(&sport->lpuart_timer, lpuart_timer_func, - (unsigned long)sport); - } else - sport->lpuart_dma_rx_use = false; - - - if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) { - sport->lpuart_dma_tx_use = true; - temp = readb(port->membase + UARTCR5); - temp &= ~UARTCR5_RDMAS; - writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5); - } else - sport->lpuart_dma_tx_use = false; - ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0, DRIVER_NAME, sport); if (ret) @@ -1113,7 +1150,29 @@ static int lpuart_startup(struct uart_port *port) temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE); writeb(temp, sport->port.membase + UARTCR2); + if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) { + /* set Rx DMA timeout */ + sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT); + if (!sport->dma_rx_timeout) + sport->dma_rx_timeout = 1; + + sport->lpuart_dma_rx_use = true; + rx_dma_timer_init(sport); + } else { + sport->lpuart_dma_rx_use = false; + } + + if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) { + init_waitqueue_head(&sport->dma_wait); + sport->lpuart_dma_tx_use = true; + temp = readb(port->membase + UARTCR5); + writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5); + } else { + sport->lpuart_dma_tx_use = false; + } + spin_unlock_irqrestore(&sport->port.lock, flags); + return 0; } @@ -1170,12 +1229,19 @@ static void lpuart_shutdown(struct uart_port *port) devm_free_irq(port->dev, port->irq, sport); if (sport->lpuart_dma_rx_use) { - lpuart_dma_rx_free(&sport->port); del_timer_sync(&sport->lpuart_timer); + lpuart_dma_rx_free(&sport->port); } - if (sport->lpuart_dma_tx_use) - lpuart_dma_tx_free(&sport->port); + if (sport->lpuart_dma_tx_use) { + if (wait_event_interruptible(sport->dma_wait, + !sport->dma_tx_in_progress) != false) { + sport->dma_tx_in_progress = false; + dmaengine_terminate_all(sport->dma_tx_chan); + } + + lpuart_stop_tx(port); + } } static void lpuart32_shutdown(struct uart_port *port) @@ -1203,13 +1269,14 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); unsigned long flags; - unsigned char cr1, old_cr1, old_cr2, cr4, bdh, modem; + unsigned char cr1, old_cr1, old_cr2, cr3, cr4, bdh, modem; unsigned int baud; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; unsigned int sbr, brfa; cr1 = old_cr1 = readb(sport->port.membase + UARTCR1); old_cr2 = readb(sport->port.membase + UARTCR2); + cr3 = readb(sport->port.membase + UARTCR3); cr4 = readb(sport->port.membase + UARTCR4); bdh = readb(sport->port.membase + UARTBDH); modem = readb(sport->port.membase + UARTMODEM); @@ -1240,6 +1307,13 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, cr1 |= UARTCR1_M; } + /* + * When auto RS-485 RTS mode is enabled, + * hardware flow control need to be disabled. + */ + if (sport->port.rs485.flags & SER_RS485_ENABLED) + termios->c_cflag &= ~CRTSCTS; + if (termios->c_cflag & CRTSCTS) { modem |= (UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); } else { @@ -1257,7 +1331,10 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, if ((termios->c_cflag & PARENB)) { if (termios->c_cflag & CMSPAR) { cr1 &= ~UARTCR1_PE; - cr1 |= UARTCR1_M; + if (termios->c_cflag & PARODD) + cr3 |= UARTCR3_T8; + else + cr3 &= ~UARTCR3_T8; } else { cr1 |= UARTCR1_PE; if ((termios->c_cflag & CSIZE) == CS8) @@ -1297,17 +1374,6 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, /* update the per-port timeout */ uart_update_timeout(port, termios->c_cflag, baud); - if (sport->lpuart_dma_rx_use) { - /* Calculate delay for 1.5 DMA buffers */ - sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) * - FSL_UART_RX_DMA_BUFFER_SIZE * 3 / - sport->rxfifo_size / 2; - dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n", - sport->dma_rx_timeout * 1000 / HZ, sport->port.timeout); - if (sport->dma_rx_timeout < msecs_to_jiffies(20)) - sport->dma_rx_timeout = msecs_to_jiffies(20); - } - /* wait transmit engin complete */ while (!(readb(sport->port.membase + UARTSR1) & UARTSR1_TC)) barrier(); @@ -1325,12 +1391,31 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, writeb(cr4 | brfa, sport->port.membase + UARTCR4); writeb(bdh, sport->port.membase + UARTBDH); writeb(sbr & 0xFF, sport->port.membase + UARTBDL); + writeb(cr3, sport->port.membase + UARTCR3); writeb(cr1, sport->port.membase + UARTCR1); writeb(modem, sport->port.membase + UARTMODEM); /* restore control register */ writeb(old_cr2, sport->port.membase + UARTCR2); + /* + * If new baud rate is set, we will also need to update the Ring buffer + * length according to the selected baud rate and restart Rx DMA path. + */ + if (old) { + if (sport->lpuart_dma_rx_use) { + del_timer_sync(&sport->lpuart_timer); + lpuart_dma_rx_free(&sport->port); + } + + if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) { + sport->lpuart_dma_rx_use = true; + rx_dma_timer_init(sport); + } else { + sport->lpuart_dma_rx_use = false; + } + } + spin_unlock_irqrestore(&sport->port.lock, flags); } @@ -1494,7 +1579,7 @@ static int lpuart_verify_port(struct uart_port *port, struct serial_struct *ser) return ret; } -static struct uart_ops lpuart_pops = { +static const struct uart_ops lpuart_pops = { .tx_empty = lpuart_tx_empty, .set_mctrl = lpuart_set_mctrl, .get_mctrl = lpuart_get_mctrl, @@ -1513,7 +1598,7 @@ static struct uart_ops lpuart_pops = { .flush_buffer = lpuart_flush_buffer, }; -static struct uart_ops lpuart32_pops = { +static const struct uart_ops lpuart32_pops = { .tx_empty = lpuart32_tx_empty, .set_mctrl = lpuart32_set_mctrl, .get_mctrl = lpuart32_get_mctrl, @@ -1843,6 +1928,8 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.ops = &lpuart_pops; sport->port.flags = UPF_BOOT_AUTOCONF; + sport->port.rs485_config = lpuart_config_rs485; + sport->clk = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->clk)) { ret = PTR_ERR(sport->clk); @@ -1883,6 +1970,12 @@ static int lpuart_probe(struct platform_device *pdev) dev_info(sport->port.dev, "DMA rx channel request failed, " "operating without rx DMA\n"); + if (of_property_read_bool(np, "linux,rs485-enabled-at-boot-time")) { + sport->port.rs485.flags |= SER_RS485_ENABLED; + sport->port.rs485.flags |= SER_RS485_RTS_ON_SEND; + writeb(UARTMODEM_TXRTSE, sport->port.membase + UARTMODEM); + } + return 0; } @@ -1923,6 +2016,32 @@ static int lpuart_suspend(struct device *dev) uart_suspend_port(&lpuart_reg, &sport->port); + if (sport->lpuart_dma_rx_use) { + /* + * EDMA driver during suspend will forcefully release any + * non-idle DMA channels. If port wakeup is enabled or if port + * is console port or 'no_console_suspend' is set the Rx DMA + * cannot resume as as expected, hence gracefully release the + * Rx DMA path before suspend and start Rx DMA path on resume. + */ + if (sport->port.irq_wake) { + del_timer_sync(&sport->lpuart_timer); + lpuart_dma_rx_free(&sport->port); + } + + /* Disable Rx DMA to use UART port as wakeup source */ + writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_RDMAS, + sport->port.membase + UARTCR5); + } + + if (sport->lpuart_dma_tx_use) { + sport->dma_tx_in_progress = false; + dmaengine_terminate_all(sport->dma_tx_chan); + } + + if (sport->port.suspended && !sport->port.irq_wake) + clk_disable_unprepare(sport->clk); + return 0; } @@ -1931,6 +2050,9 @@ static int lpuart_resume(struct device *dev) struct lpuart_port *sport = dev_get_drvdata(dev); unsigned long temp; + if (sport->port.suspended && !sport->port.irq_wake) + clk_prepare_enable(sport->clk); + if (sport->lpuart32) { lpuart32_setup_watermark(sport); temp = lpuart32_read(sport->port.membase + UARTCTRL); @@ -1944,6 +2066,26 @@ static int lpuart_resume(struct device *dev) writeb(temp, sport->port.membase + UARTCR2); } + if (sport->lpuart_dma_rx_use) { + if (sport->port.irq_wake) { + if (!lpuart_start_rx_dma(sport)) { + sport->lpuart_dma_rx_use = true; + rx_dma_timer_init(sport); + } else { + sport->lpuart_dma_rx_use = false; + } + } + } + + if (sport->dma_tx_chan && !lpuart_dma_tx_request(&sport->port)) { + init_waitqueue_head(&sport->dma_wait); + sport->lpuart_dma_tx_use = true; + writeb(readb(sport->port.membase + UARTCR5) | + UARTCR5_TDMAS, sport->port.membase + UARTCR5); + } else { + sport->lpuart_dma_tx_use = false; + } + uart_resume_port(&lpuart_reg, &sport->port); return 0; diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 0df2b1c091ae..a70356dad1b7 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -190,6 +190,7 @@ enum imx_uart_type { IMX1_UART, IMX21_UART, + IMX53_UART, IMX6Q_UART, }; @@ -222,6 +223,9 @@ struct imx_port { struct dma_chan *dma_chan_rx, *dma_chan_tx; struct scatterlist rx_sgl, tx_sgl[2]; void *rx_buf; + struct circ_buf rx_ring; + unsigned int rx_periods; + dma_cookie_t rx_cookie; unsigned int tx_bytes; unsigned int dma_tx_nents; wait_queue_head_t dma_wait; @@ -244,6 +248,10 @@ static struct imx_uart_data imx_uart_devdata[] = { .uts_reg = IMX21_UTS, .devtype = IMX21_UART, }, + [IMX53_UART] = { + .uts_reg = IMX21_UTS, + .devtype = IMX53_UART, + }, [IMX6Q_UART] = { .uts_reg = IMX21_UTS, .devtype = IMX6Q_UART, @@ -258,6 +266,9 @@ static const struct platform_device_id imx_uart_devtype[] = { .name = "imx21-uart", .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART], }, { + .name = "imx53-uart", + .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX53_UART], + }, { .name = "imx6q-uart", .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX6Q_UART], }, { @@ -268,6 +279,7 @@ MODULE_DEVICE_TABLE(platform, imx_uart_devtype); static const struct of_device_id imx_uart_dt_ids[] = { { .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], }, + { .compatible = "fsl,imx53-uart", .data = &imx_uart_devdata[IMX53_UART], }, { .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], }, { .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], }, { /* sentinel */ } @@ -289,6 +301,11 @@ static inline int is_imx21_uart(struct imx_port *sport) return sport->devdata->devtype == IMX21_UART; } +static inline int is_imx53_uart(struct imx_port *sport) +{ + return sport->devdata->devtype == IMX53_UART; +} + static inline int is_imx6q_uart(struct imx_port *sport) { return sport->devdata->devtype == IMX6Q_UART; @@ -701,6 +718,7 @@ out: return IRQ_HANDLED; } +static void clear_rx_errors(struct imx_port *sport); static int start_rx_dma(struct imx_port *sport); /* * If the RXFIFO is filled with some data, and then we @@ -726,6 +744,11 @@ static void imx_dma_rxint(struct imx_port *sport) temp &= ~(UCR2_ATEN); writel(temp, sport->port.membase + UCR2); + /* disable the rx errors interrupts */ + temp = readl(sport->port.membase + UCR4); + temp &= ~UCR4_OREN; + writel(temp, sport->port.membase + UCR4); + /* tell the DMA to receive the data. */ start_rx_dma(sport); } @@ -740,12 +763,13 @@ static unsigned int imx_get_hwmctrl(struct imx_port *sport) { unsigned int tmp = TIOCM_DSR; unsigned usr1 = readl(sport->port.membase + USR1); + unsigned usr2 = readl(sport->port.membase + USR2); if (usr1 & USR1_RTSS) tmp |= TIOCM_CTS; /* in DCE mode DCDIN is always 0 */ - if (!(usr1 & USR2_DCDIN)) + if (!(usr2 & USR2_DCDIN)) tmp |= TIOCM_CAR; if (sport->dte_mode) @@ -932,30 +956,6 @@ static void imx_timeout(unsigned long data) } #define RX_BUF_SIZE (PAGE_SIZE) -static void imx_rx_dma_done(struct imx_port *sport) -{ - unsigned long temp; - unsigned long flags; - - spin_lock_irqsave(&sport->port.lock, flags); - - /* re-enable interrupts to get notified when new symbols are incoming */ - temp = readl(sport->port.membase + UCR1); - temp |= UCR1_RRDYEN; - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR2); - temp |= UCR2_ATEN; - writel(temp, sport->port.membase + UCR2); - - sport->dma_is_rxing = 0; - - /* Is the shutdown waiting for us? */ - if (waitqueue_active(&sport->dma_wait)) - wake_up(&sport->dma_wait); - - spin_unlock_irqrestore(&sport->port.lock, flags); -} /* * There are two kinds of RX DMA interrupts(such as in the MX6Q): @@ -972,43 +972,76 @@ static void dma_rx_callback(void *data) struct scatterlist *sgl = &sport->rx_sgl; struct tty_port *port = &sport->port.state->port; struct dma_tx_state state; + struct circ_buf *rx_ring = &sport->rx_ring; enum dma_status status; - unsigned int count; - - /* unmap it first */ - dma_unmap_sg(sport->port.dev, sgl, 1, DMA_FROM_DEVICE); + unsigned int w_bytes = 0; + unsigned int r_bytes; + unsigned int bd_size; status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state); - count = RX_BUF_SIZE - state.residue; - dev_dbg(sport->port.dev, "We get %d bytes.\n", count); + if (status == DMA_ERROR) { + dev_err(sport->port.dev, "DMA transaction error.\n"); + clear_rx_errors(sport); + return; + } + + if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) { + + /* + * The state-residue variable represents the empty space + * relative to the entire buffer. Taking this in consideration + * the head is always calculated base on the buffer total + * length - DMA transaction residue. The UART script from the + * SDMA firmware will jump to the next buffer descriptor, + * once a DMA transaction if finalized (IMX53 RM - A.4.1.2.4). + * Taking this in consideration the tail is always at the + * beginning of the buffer descriptor that contains the head. + */ + + /* Calculate the head */ + rx_ring->head = sg_dma_len(sgl) - state.residue; + + /* Calculate the tail. */ + bd_size = sg_dma_len(sgl) / sport->rx_periods; + rx_ring->tail = ((rx_ring->head-1) / bd_size) * bd_size; + + if (rx_ring->head <= sg_dma_len(sgl) && + rx_ring->head > rx_ring->tail) { + + /* Move data from tail to head */ + r_bytes = rx_ring->head - rx_ring->tail; - if (count) { - if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) { - int bytes = tty_insert_flip_string(port, sport->rx_buf, - count); + /* CPU claims ownership of RX DMA buffer */ + dma_sync_sg_for_cpu(sport->port.dev, sgl, 1, + DMA_FROM_DEVICE); - if (bytes != count) + w_bytes = tty_insert_flip_string(port, + sport->rx_buf + rx_ring->tail, r_bytes); + + /* UART retrieves ownership of RX DMA buffer */ + dma_sync_sg_for_device(sport->port.dev, sgl, 1, + DMA_FROM_DEVICE); + + if (w_bytes != r_bytes) sport->port.icount.buf_overrun++; + + sport->port.icount.rx += w_bytes; + } else { + WARN_ON(rx_ring->head > sg_dma_len(sgl)); + WARN_ON(rx_ring->head <= rx_ring->tail); } - tty_flip_buffer_push(port); - sport->port.icount.rx += count; } - /* - * Restart RX DMA directly if more data is available in order to skip - * the roundtrip through the IRQ handler. If there is some data already - * in the FIFO, DMA needs to be restarted soon anyways. - * - * Otherwise stop the DMA and reactivate FIFO IRQs to restart DMA once - * data starts to arrive again. - */ - if (readl(sport->port.membase + USR2) & USR2_RDR) - start_rx_dma(sport); - else - imx_rx_dma_done(sport); + if (w_bytes) { + tty_flip_buffer_push(port); + dev_dbg(sport->port.dev, "We get %d bytes.\n", w_bytes); + } } +/* RX DMA buffer periods */ +#define RX_DMA_PERIODS 4 + static int start_rx_dma(struct imx_port *sport) { struct scatterlist *sgl = &sport->rx_sgl; @@ -1017,14 +1050,21 @@ static int start_rx_dma(struct imx_port *sport) struct dma_async_tx_descriptor *desc; int ret; + sport->rx_ring.head = 0; + sport->rx_ring.tail = 0; + sport->rx_periods = RX_DMA_PERIODS; + sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE); ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE); if (ret == 0) { dev_err(dev, "DMA mapping error for RX.\n"); return -EINVAL; } - desc = dmaengine_prep_slave_sg(chan, sgl, 1, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT); + + desc = dmaengine_prep_dma_cyclic(chan, sg_dma_address(sgl), + sg_dma_len(sgl), sg_dma_len(sgl) / sport->rx_periods, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); + if (!desc) { dma_unmap_sg(dev, sgl, 1, DMA_FROM_DEVICE); dev_err(dev, "We cannot prepare for the RX slave dma!\n"); @@ -1034,11 +1074,36 @@ static int start_rx_dma(struct imx_port *sport) desc->callback_param = sport; dev_dbg(dev, "RX: prepare for the DMA.\n"); - dmaengine_submit(desc); + sport->rx_cookie = dmaengine_submit(desc); dma_async_issue_pending(chan); return 0; } +static void clear_rx_errors(struct imx_port *sport) +{ + unsigned int status_usr1, status_usr2; + + status_usr1 = readl(sport->port.membase + USR1); + status_usr2 = readl(sport->port.membase + USR2); + + if (status_usr2 & USR2_BRCD) { + sport->port.icount.brk++; + writel(USR2_BRCD, sport->port.membase + USR2); + } else if (status_usr1 & USR1_FRAMERR) { + sport->port.icount.frame++; + writel(USR1_FRAMERR, sport->port.membase + USR1); + } else if (status_usr1 & USR1_PARITYERR) { + sport->port.icount.parity++; + writel(USR1_PARITYERR, sport->port.membase + USR1); + } + + if (status_usr2 & USR2_ORE) { + sport->port.icount.overrun++; + writel(USR2_ORE, sport->port.membase + USR2); + } + +} + #define TXTL_DEFAULT 2 /* reset default */ #define RXTL_DEFAULT 1 /* reset default */ #define TXTL_DMA 8 /* DMA burst setting */ @@ -1058,14 +1123,16 @@ static void imx_setup_ufcr(struct imx_port *sport, static void imx_uart_dma_exit(struct imx_port *sport) { if (sport->dma_chan_rx) { + dmaengine_terminate_sync(sport->dma_chan_rx); dma_release_channel(sport->dma_chan_rx); sport->dma_chan_rx = NULL; - + sport->rx_cookie = -EINVAL; kfree(sport->rx_buf); sport->rx_buf = NULL; } if (sport->dma_chan_tx) { + dmaengine_terminate_sync(sport->dma_chan_tx); dma_release_channel(sport->dma_chan_tx); sport->dma_chan_tx = NULL; } @@ -1103,6 +1170,7 @@ static int imx_uart_dma_init(struct imx_port *sport) ret = -ENOMEM; goto err; } + sport->rx_ring.buf = sport->rx_buf; /* Prepare for TX : */ sport->dma_chan_tx = dma_request_slave_channel(dev, "tx"); @@ -1201,8 +1269,7 @@ static int imx_startup(struct uart_port *port) writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); /* Can we enable the DMA support? */ - if (is_imx6q_uart(sport) && !uart_console(port) && - !sport->dma_is_inited) + if (!uart_console(port) && !sport->dma_is_inited) imx_uart_dma_init(sport); spin_lock_irqsave(&sport->port.lock, flags); @@ -1283,17 +1350,11 @@ static void imx_shutdown(struct uart_port *port) unsigned long flags; if (sport->dma_is_enabled) { - int ret; + sport->dma_is_rxing = 0; + sport->dma_is_txing = 0; + dmaengine_terminate_sync(sport->dma_chan_tx); + dmaengine_terminate_sync(sport->dma_chan_rx); - /* We have to wait for the DMA to finish. */ - ret = wait_event_interruptible(sport->dma_wait, - !sport->dma_is_rxing && !sport->dma_is_txing); - if (ret != 0) { - sport->dma_is_rxing = 0; - sport->dma_is_txing = 0; - dmaengine_terminate_all(sport->dma_chan_tx); - dmaengine_terminate_all(sport->dma_chan_rx); - } spin_lock_irqsave(&sport->port.lock, flags); imx_stop_tx(port); imx_stop_rx(port); @@ -1690,7 +1751,7 @@ static int imx_rs485_config(struct uart_port *port, return 0; } -static struct uart_ops imx_pops = { +static const struct uart_ops imx_pops = { .tx_empty = imx_tx_empty, .set_mctrl = imx_set_mctrl, .get_mctrl = imx_get_mctrl, @@ -2077,8 +2138,10 @@ static int serial_imx_probe(struct platform_device *pdev) /* For register access, we only need to enable the ipg clock. */ ret = clk_prepare_enable(sport->clk_ipg); - if (ret) + if (ret) { + dev_err(&pdev->dev, "failed to enable per clk: %d\n", ret); return ret; + } /* Disable interrupts before requesting them */ reg = readl_relaxed(sport->port.membase + UCR1); @@ -2095,18 +2158,26 @@ static int serial_imx_probe(struct platform_device *pdev) if (txirq > 0) { ret = devm_request_irq(&pdev->dev, rxirq, imx_rxint, 0, dev_name(&pdev->dev), sport); - if (ret) + if (ret) { + dev_err(&pdev->dev, "failed to request rx irq: %d\n", + ret); return ret; + } ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0, dev_name(&pdev->dev), sport); - if (ret) + if (ret) { + dev_err(&pdev->dev, "failed to request tx irq: %d\n", + ret); return ret; + } } else { ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0, dev_name(&pdev->dev), sport); - if (ret) + if (ret) { + dev_err(&pdev->dev, "failed to request irq: %d\n", ret); return ret; + } } imx_ports[sport->port.line] = sport; diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index c5ddfe542451..ec7d8383900f 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -346,7 +346,7 @@ static void jsm_config_port(struct uart_port *port, int flags) port->type = PORT_JSM; } -static struct uart_ops jsm_ops = { +static const struct uart_ops jsm_ops = { .tx_empty = jsm_tty_tx_empty, .set_mctrl = jsm_tty_set_mctrl, .get_mctrl = jsm_tty_get_mctrl, diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 5c4c280b3207..ace82645b123 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -712,7 +712,7 @@ static void max3100_break_ctl(struct uart_port *port, int break_state) dev_dbg(&s->spi->dev, "%s\n", __func__); } -static struct uart_ops max3100_ops = { +static const struct uart_ops max3100_ops = { .tx_empty = max3100_tx_empty, .set_mctrl = max3100_set_mctrl, .get_mctrl = max3100_get_mctrl, diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 9360801df3c4..8a3e92638e10 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1329,9 +1329,9 @@ static int max310x_spi_probe(struct spi_device *spi) const struct spi_device_id *id_entry = spi_get_device_id(spi); devtype = (struct max310x_devtype *)id_entry->driver_data; - flags = IRQF_TRIGGER_FALLING; } + flags = IRQF_TRIGGER_FALLING; regcfg.max_register = devtype->nr * 0x20 - 1; regmap = devm_regmap_init_spi(spi, ®cfg); diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c index a44290e9b5a8..e72ea61c70db 100644 --- a/drivers/tty/serial/men_z135_uart.c +++ b/drivers/tty/serial/men_z135_uart.c @@ -775,7 +775,7 @@ static int men_z135_verify_port(struct uart_port *port, return -EINVAL; } -static struct uart_ops men_z135_ops = { +static const struct uart_ops men_z135_ops = { .tx_empty = men_z135_tx_empty, .set_mctrl = men_z135_set_mctrl, .get_mctrl = men_z135_get_mctrl, diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index eb54e5c77ead..770454e0dfa3 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1317,7 +1317,7 @@ static void mxs_auart_break_ctl(struct uart_port *u, int ctl) mxs_clr(AUART_LINECTRL_BRK, s, REG_LINECTRL); } -static struct uart_ops mxs_auart_ops = { +static const struct uart_ops mxs_auart_ops = { .tx_empty = mxs_auart_tx_empty, .start_tx = mxs_auart_start_tx, .stop_tx = mxs_auart_stop_tx, @@ -1510,10 +1510,7 @@ static int mxs_get_clks(struct mxs_auart_port *s, if (!is_asm9260_auart(s)) { s->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(s->clk)) - return PTR_ERR(s->clk); - - return 0; + return PTR_ERR_OR_ZERO(s->clk); } s->clk = devm_clk_get(s->dev, "mod"); @@ -1537,16 +1534,20 @@ static int mxs_get_clks(struct mxs_auart_port *s, err = clk_set_rate(s->clk, clk_get_rate(s->clk_ahb)); if (err) { dev_err(s->dev, "Failed to set rate!\n"); - return err; + goto disable_clk_ahb; } err = clk_prepare_enable(s->clk); if (err) { dev_err(s->dev, "Failed to enable clk!\n"); - return err; + goto disable_clk_ahb; } return 0; + +disable_clk_ahb: + clk_disable_unprepare(s->clk_ahb); + return err; } /* diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 23672f8a343e..d391650b82e7 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1604,7 +1604,7 @@ static void pch_uart_put_poll_char(struct uart_port *port, } #endif /* CONFIG_CONSOLE_POLL */ -static struct uart_ops pch_uart_ops = { +static const struct uart_ops pch_uart_ops = { .tx_empty = pch_uart_tx_empty, .set_mctrl = pch_uart_set_mctrl, .get_mctrl = pch_uart_get_mctrl, diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index ae2095a66708..f44615fa474d 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1577,7 +1577,7 @@ static void s3c24xx_serial_resetport(struct uart_port *port, } -#ifdef CONFIG_CPU_FREQ +#ifdef CONFIG_ARM_S3C24XX_CPUFREQ static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data) diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h index 2ae4fcee1814..a04acef1cb20 100644 --- a/drivers/tty/serial/samsung.h +++ b/drivers/tty/serial/samsung.h @@ -102,7 +102,7 @@ struct s3c24xx_uart_port { struct s3c24xx_uart_dma *dma; -#ifdef CONFIG_CPU_FREQ +#ifdef CONFIG_ARM_S3C24XX_CPUFREQ struct notifier_block freq_transition; #endif }; diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index f36e6df2fa90..a9d94f7cf683 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1205,6 +1205,10 @@ static int sc16is7xx_probe(struct device *dev, } #endif + /* reset device, purging any pending irq / data */ + regmap_write(s->regmap, SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT, + SC16IS7XX_IOCONTROL_SRESET_BIT); + for (i = 0; i < devtype->nr_uart; ++i) { s->p[i].line = i; /* Initialize port data */ @@ -1234,6 +1238,22 @@ static int sc16is7xx_probe(struct device *dev, init_kthread_work(&s->p[i].reg_work, sc16is7xx_reg_proc); /* Register port */ uart_add_one_port(&sc16is7xx_uart, &s->p[i].port); + + /* Enable EFR */ + sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, + SC16IS7XX_LCR_CONF_MODE_B); + + regcache_cache_bypass(s->regmap, true); + + /* Enable write access to enhanced features */ + sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFR_REG, + SC16IS7XX_EFR_ENABLE_BIT); + + regcache_cache_bypass(s->regmap, false); + + /* Restore access to general registers */ + sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, 0x00); + /* Go to suspend mode */ sc16is7xx_power(&s->p[i].port, 0); } diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 9fc15335c8c5..6e4f63627479 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -235,18 +235,9 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state, if (tty_port_initialized(port)) return 0; - /* - * Set the TTY IO error marker - we will only clear this - * once we have successfully opened the port. - */ - set_bit(TTY_IO_ERROR, &tty->flags); - retval = uart_port_startup(tty, state, init_hw); - if (!retval) { - tty_port_set_initialized(port, 1); - clear_bit(TTY_IO_ERROR, &tty->flags); - } else if (retval > 0) - retval = 0; + if (retval) + set_bit(TTY_IO_ERROR, &tty->flags); return retval; } @@ -972,8 +963,11 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, } uart_change_speed(tty, state, NULL); } - } else + } else { retval = uart_startup(tty, state, 1); + if (retval > 0) + retval = 0; + } exit: return retval; } @@ -1139,6 +1133,8 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) uport->ops->config_port(uport, flags); ret = uart_startup(tty, state, 1); + if (ret > 0) + ret = 0; } out: mutex_unlock(&port->mutex); @@ -1465,7 +1461,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp) { struct uart_state *state = tty->driver_data; struct tty_port *port; - struct uart_port *uport; if (!state) { struct uart_driver *drv = tty->driver->driver_state; @@ -1481,56 +1476,36 @@ static void uart_close(struct tty_struct *tty, struct file *filp) port = &state->port; pr_debug("uart_close(%d) called\n", tty->index); - if (tty_port_close_start(port, tty, filp) == 0) - return; + tty_port_close(tty->port, tty, filp); +} - mutex_lock(&port->mutex); - uport = uart_port_check(state); +static void uart_tty_port_shutdown(struct tty_port *port) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = uart_port_check(state); /* * At this point, we stop accepting input. To do this, we * disable the receive line status interrupts. */ - if (tty_port_initialized(port) && - !WARN(!uport, "detached port still initialized!\n")) { - spin_lock_irq(&uport->lock); - uport->ops->stop_rx(uport); - spin_unlock_irq(&uport->lock); - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - uart_wait_until_sent(tty, uport->timeout); - } - - uart_shutdown(tty, state); - tty_port_tty_set(port, NULL); + if (WARN(!uport, "detached port still initialized!\n")) + return; - spin_lock_irq(&port->lock); + spin_lock_irq(&uport->lock); + uport->ops->stop_rx(uport); + spin_unlock_irq(&uport->lock); - if (port->blocked_open) { - spin_unlock_irq(&port->lock); - if (port->close_delay) - msleep_interruptible(jiffies_to_msecs(port->close_delay)); - spin_lock_irq(&port->lock); - } else if (uport && !uart_console(uport)) { - spin_unlock_irq(&port->lock); - uart_change_pm(state, UART_PM_STATE_OFF); - spin_lock_irq(&port->lock); - } - spin_unlock_irq(&port->lock); - tty_port_set_active(port, 0); + uart_port_shutdown(port); /* - * Wake up anyone trying to open this port. + * It's possible for shutdown to be called after suspend if we get + * a DCD drop (hangup) at just the right time. Clear suspended bit so + * we don't try to resume a port that has been shutdown. */ - wake_up_interruptible(&port->open_wait); + tty_port_set_suspended(port, 0); - mutex_unlock(&port->mutex); + uart_change_pm(state, UART_PM_STATE_OFF); - tty_ldisc_flush(tty); - tty->closing = 0; } static void uart_wait_until_sent(struct tty_struct *tty, int timeout) @@ -1711,52 +1686,31 @@ static int uart_open(struct tty_struct *tty, struct file *filp) struct uart_driver *drv = tty->driver->driver_state; int retval, line = tty->index; struct uart_state *state = drv->state + line; - struct tty_port *port = &state->port; - struct uart_port *uport; - pr_debug("uart_open(%d) called\n", line); + tty->driver_data = state; - spin_lock_irq(&port->lock); - ++port->count; - spin_unlock_irq(&port->lock); + retval = tty_port_open(&state->port, tty, filp); + if (retval > 0) + retval = 0; - /* - * We take the semaphore here to guarantee that we won't be re-entered - * while allocating the state structure, or while we request any IRQs - * that the driver may need. This also has the nice side-effect that - * it delays the action of uart_hangup, so we can guarantee that - * state->port.tty will always contain something reasonable. - */ - if (mutex_lock_interruptible(&port->mutex)) { - retval = -ERESTARTSYS; - goto end; - } + return retval; +} + +static int uart_port_activate(struct tty_port *port, struct tty_struct *tty) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport; uport = uart_port_check(state); - if (!uport || uport->flags & UPF_DEAD) { - retval = -ENXIO; - goto err_unlock; - } + if (!uport || uport->flags & UPF_DEAD) + return -ENXIO; - tty->driver_data = state; - uport->state = state; port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; - tty_port_tty_set(port, tty); /* * Start up the serial port. */ - retval = uart_startup(tty, state, 0); - - /* - * If we succeeded, wait until the port is ready. - */ -err_unlock: - mutex_unlock(&port->mutex); - if (retval == 0) - retval = tty_port_block_til_ready(port, tty, filp); -end: - return retval; + return uart_startup(tty, state, 0); } static const char *uart_type(struct uart_port *port) @@ -1940,7 +1894,7 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) * * Returns 0 on success or -EINVAL on failure */ -int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr, +int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr, char **options) { if (strncmp(p, "mmio,", 5) == 0) { @@ -1968,7 +1922,11 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr, return -EINVAL; } - *addr = simple_strtoul(p, NULL, 0); + /* + * Before you replace it with kstrtoull(), think about options separator + * (',') it will not tolerate + */ + *addr = simple_strtoull(p, NULL, 0); p = strchr(p, ','); if (p) p++; @@ -2470,6 +2428,8 @@ static const struct tty_operations uart_ops = { static const struct tty_port_operations uart_port_ops = { .carrier_raised = uart_carrier_raised, .dtr_rts = uart_dtr_rts, + .activate = uart_port_activate, + .shutdown = uart_tty_port_shutdown, }; /** @@ -2786,6 +2746,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) uport->cons = drv->cons; uport->minor = drv->tty_driver->minor_start + uport->line; + port->console = uart_console(uport); + /* * If this port is a console, then the spinlock is already * initialised. diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index d86eee38aae6..4b26252c2885 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2533,7 +2533,7 @@ static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) return 0; } -static struct uart_ops sci_uart_ops = { +static const struct uart_ops sci_uart_ops = { .tx_empty = sci_tx_empty, .set_mctrl = sci_set_mctrl, .get_mctrl = sci_get_mctrl, diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index 2d78cb3627ae..379e5bd37df9 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -639,7 +639,7 @@ static void asc_put_poll_char(struct uart_port *port, unsigned char c) /*---------------------------------------------------------------------*/ -static struct uart_ops asc_uart_ops = { +static const struct uart_ops asc_uart_ops = { .tx_empty = asc_tx_empty, .set_mctrl = asc_set_mctrl, .get_mctrl = asc_get_mctrl, diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index f89d1f79be18..033856287ca2 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -1,6 +1,7 @@ /* * Copyright (C) Maxime Coquelin 2015 - * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com> + * Authors: Maxime Coquelin <mcoquelin.stm32@gmail.com> + * Gerald Baeza <gerald.baeza@st.com> * License terms: GNU General Public License (GPL), version 2 * * Inspired by st-asc.c from STMicroelectronics (c) @@ -10,120 +11,31 @@ #define SUPPORT_SYSRQ #endif -#include <linux/module.h> -#include <linux/serial.h> +#include <linux/clk.h> #include <linux/console.h> -#include <linux/sysrq.h> -#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/dma-direction.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/irq.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/delay.h> -#include <linux/spinlock.h> -#include <linux/pm_runtime.h> +#include <linux/module.h> #include <linux/of.h> #include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/serial_core.h> -#include <linux/clk.h> - -#define DRIVER_NAME "stm32-usart" - -/* Register offsets */ -#define USART_SR 0x00 -#define USART_DR 0x04 -#define USART_BRR 0x08 -#define USART_CR1 0x0c -#define USART_CR2 0x10 -#define USART_CR3 0x14 -#define USART_GTPR 0x18 - -/* USART_SR */ -#define USART_SR_PE BIT(0) -#define USART_SR_FE BIT(1) -#define USART_SR_NF BIT(2) -#define USART_SR_ORE BIT(3) -#define USART_SR_IDLE BIT(4) -#define USART_SR_RXNE BIT(5) -#define USART_SR_TC BIT(6) -#define USART_SR_TXE BIT(7) -#define USART_SR_LBD BIT(8) -#define USART_SR_CTS BIT(9) -#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \ - USART_SR_FE | USART_SR_PE) -/* Dummy bits */ -#define USART_SR_DUMMY_RX BIT(16) - -/* USART_DR */ -#define USART_DR_MASK GENMASK(8, 0) - -/* USART_BRR */ -#define USART_BRR_DIV_F_MASK GENMASK(3, 0) -#define USART_BRR_DIV_M_MASK GENMASK(15, 4) -#define USART_BRR_DIV_M_SHIFT 4 - -/* USART_CR1 */ -#define USART_CR1_SBK BIT(0) -#define USART_CR1_RWU BIT(1) -#define USART_CR1_RE BIT(2) -#define USART_CR1_TE BIT(3) -#define USART_CR1_IDLEIE BIT(4) -#define USART_CR1_RXNEIE BIT(5) -#define USART_CR1_TCIE BIT(6) -#define USART_CR1_TXEIE BIT(7) -#define USART_CR1_PEIE BIT(8) -#define USART_CR1_PS BIT(9) -#define USART_CR1_PCE BIT(10) -#define USART_CR1_WAKE BIT(11) -#define USART_CR1_M BIT(12) -#define USART_CR1_UE BIT(13) -#define USART_CR1_OVER8 BIT(15) -#define USART_CR1_IE_MASK GENMASK(8, 4) - -/* USART_CR2 */ -#define USART_CR2_ADD_MASK GENMASK(3, 0) -#define USART_CR2_LBDL BIT(5) -#define USART_CR2_LBDIE BIT(6) -#define USART_CR2_LBCL BIT(8) -#define USART_CR2_CPHA BIT(9) -#define USART_CR2_CPOL BIT(10) -#define USART_CR2_CLKEN BIT(11) -#define USART_CR2_STOP_2B BIT(13) -#define USART_CR2_STOP_MASK GENMASK(13, 12) -#define USART_CR2_LINEN BIT(14) - -/* USART_CR3 */ -#define USART_CR3_EIE BIT(0) -#define USART_CR3_IREN BIT(1) -#define USART_CR3_IRLP BIT(2) -#define USART_CR3_HDSEL BIT(3) -#define USART_CR3_NACK BIT(4) -#define USART_CR3_SCEN BIT(5) -#define USART_CR3_DMAR BIT(6) -#define USART_CR3_DMAT BIT(7) -#define USART_CR3_RTSE BIT(8) -#define USART_CR3_CTSE BIT(9) -#define USART_CR3_CTSIE BIT(10) -#define USART_CR3_ONEBIT BIT(11) - -/* USART_GTPR */ -#define USART_GTPR_PSC_MASK GENMASK(7, 0) -#define USART_GTPR_GT_MASK GENMASK(15, 8) - -#define DRIVER_NAME "stm32-usart" -#define STM32_SERIAL_NAME "ttyS" -#define STM32_MAX_PORTS 6 - -struct stm32_port { - struct uart_port port; - struct clk *clk; - bool hw_flow_control; -}; +#include <linux/serial.h> +#include <linux/spinlock.h> +#include <linux/sysrq.h> +#include <linux/tty_flip.h> +#include <linux/tty.h> -static struct stm32_port stm32_ports[STM32_MAX_PORTS]; -static struct uart_driver stm32_usart_driver; +#include "stm32-usart.h" static void stm32_stop_tx(struct uart_port *port); +static void stm32_transmit_chars(struct uart_port *port); static inline struct stm32_port *to_stm32_port(struct uart_port *port) { @@ -148,19 +60,64 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits) writel_relaxed(val, port->membase + reg); } -static void stm32_receive_chars(struct uart_port *port) +static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res, + bool threaded) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + enum dma_status status; + struct dma_tx_state state; + + *sr = readl_relaxed(port->membase + ofs->isr); + + if (threaded && stm32_port->rx_ch) { + status = dmaengine_tx_status(stm32_port->rx_ch, + stm32_port->rx_ch->cookie, + &state); + if ((status == DMA_IN_PROGRESS) && + (*last_res != state.residue)) + return 1; + else + return 0; + } else if (*sr & USART_SR_RXNE) { + return 1; + } + return 0; +} + +static unsigned long +stm32_get_char(struct uart_port *port, u32 *sr, int *last_res) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + unsigned long c; + + if (stm32_port->rx_ch) { + c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--]; + if ((*last_res) == 0) + *last_res = RX_BUF_L; + return c; + } else { + return readl_relaxed(port->membase + ofs->rdr); + } +} + +static void stm32_receive_chars(struct uart_port *port, bool threaded) { struct tty_port *tport = &port->state->port; + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long c; u32 sr; char flag; + static int last_res = RX_BUF_L; if (port->irq_wake) pm_wakeup_event(tport->tty->dev, 0); - while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) { + while (stm32_pending_rx(port, &sr, &last_res, threaded)) { sr |= USART_SR_DUMMY_RX; - c = readl_relaxed(port->membase + USART_DR); + c = stm32_get_char(port, &sr, &last_res); flag = TTY_NORMAL; port->icount.rx++; @@ -170,6 +127,10 @@ static void stm32_receive_chars(struct uart_port *port) if (uart_handle_break(port)) continue; } else if (sr & USART_SR_ORE) { + if (ofs->icr != UNDEF_REG) + writel_relaxed(USART_ICR_ORECF, + port->membase + + ofs->icr); port->icount.overrun++; } else if (sr & USART_SR_PE) { port->icount.parity++; @@ -197,14 +158,138 @@ static void stm32_receive_chars(struct uart_port *port) spin_lock(&port->lock); } +static void stm32_tx_dma_complete(void *arg) +{ + struct uart_port *port = arg; + struct stm32_port *stm32port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + unsigned int isr; + int ret; + + ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, + isr, + (isr & USART_SR_TC), + 10, 100000); + + if (ret) + dev_err(port->dev, "terminal count not set\n"); + + if (ofs->icr == UNDEF_REG) + stm32_clr_bits(port, ofs->isr, USART_SR_TC); + else + stm32_set_bits(port, ofs->icr, USART_CR_TC); + + stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + stm32port->tx_dma_busy = false; + + /* Let's see if we have pending data to send */ + stm32_transmit_chars(port); +} + +static void stm32_transmit_chars_pio(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct circ_buf *xmit = &port->state->xmit; + unsigned int isr; + int ret; + + if (stm32_port->tx_dma_busy) { + stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + stm32_port->tx_dma_busy = false; + } + + ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, + isr, + (isr & USART_SR_TXE), + 10, 100); + + if (ret) + dev_err(port->dev, "tx empty not set\n"); + + stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE); + + writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; +} + +static void stm32_transmit_chars_dma(struct uart_port *port) +{ + struct stm32_port *stm32port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + struct circ_buf *xmit = &port->state->xmit; + struct dma_async_tx_descriptor *desc = NULL; + dma_cookie_t cookie; + unsigned int count, i; + + if (stm32port->tx_dma_busy) + return; + + stm32port->tx_dma_busy = true; + + count = uart_circ_chars_pending(xmit); + + if (count > TX_BUF_L) + count = TX_BUF_L; + + if (xmit->tail < xmit->head) { + memcpy(&stm32port->tx_buf[0], &xmit->buf[xmit->tail], count); + } else { + size_t one = UART_XMIT_SIZE - xmit->tail; + size_t two; + + if (one > count) + one = count; + two = count - one; + + memcpy(&stm32port->tx_buf[0], &xmit->buf[xmit->tail], one); + if (two) + memcpy(&stm32port->tx_buf[one], &xmit->buf[0], two); + } + + desc = dmaengine_prep_slave_single(stm32port->tx_ch, + stm32port->tx_dma_buf, + count, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT); + + if (!desc) { + for (i = count; i > 0; i--) + stm32_transmit_chars_pio(port); + return; + } + + desc->callback = stm32_tx_dma_complete; + desc->callback_param = port; + + /* Push current DMA TX transaction in the pending queue */ + cookie = dmaengine_submit(desc); + + /* Issue pending DMA TX requests */ + dma_async_issue_pending(stm32port->tx_ch); + + stm32_clr_bits(port, ofs->isr, USART_SR_TC); + stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT); + + xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); + port->icount.tx += count; +} + static void stm32_transmit_chars(struct uart_port *port) { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct circ_buf *xmit = &port->state->xmit; if (port->x_char) { - writel_relaxed(port->x_char, port->membase + USART_DR); + if (stm32_port->tx_dma_busy) + stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + writel_relaxed(port->x_char, port->membase + ofs->tdr); port->x_char = 0; port->icount.tx++; + if (stm32_port->tx_dma_busy) + stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT); return; } @@ -218,9 +303,10 @@ static void stm32_transmit_chars(struct uart_port *port) return; } - writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; + if (stm32_port->tx_ch) + stm32_transmit_chars_dma(port); + else + stm32_transmit_chars_pio(port); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); @@ -232,34 +318,60 @@ static void stm32_transmit_chars(struct uart_port *port) static irqreturn_t stm32_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; u32 sr; spin_lock(&port->lock); - sr = readl_relaxed(port->membase + USART_SR); + sr = readl_relaxed(port->membase + ofs->isr); - if (sr & USART_SR_RXNE) - stm32_receive_chars(port); + if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch)) + stm32_receive_chars(port, false); - if (sr & USART_SR_TXE) + if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) stm32_transmit_chars(port); spin_unlock(&port->lock); + if (stm32_port->rx_ch) + return IRQ_WAKE_THREAD; + else + return IRQ_HANDLED; +} + +static irqreturn_t stm32_threaded_interrupt(int irq, void *ptr) +{ + struct uart_port *port = ptr; + struct stm32_port *stm32_port = to_stm32_port(port); + + spin_lock(&port->lock); + + if (stm32_port->rx_ch) + stm32_receive_chars(port, true); + + spin_unlock(&port->lock); + return IRQ_HANDLED; } static unsigned int stm32_tx_empty(struct uart_port *port) { - return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE; + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + return readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE; } static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl) { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) - stm32_set_bits(port, USART_CR3, USART_CR3_RTSE); + stm32_set_bits(port, ofs->cr3, USART_CR3_RTSE); else - stm32_clr_bits(port, USART_CR3, USART_CR3_RTSE); + stm32_clr_bits(port, ofs->cr3, USART_CR3_RTSE); } static unsigned int stm32_get_mctrl(struct uart_port *port) @@ -271,7 +383,10 @@ static unsigned int stm32_get_mctrl(struct uart_port *port) /* Transmit stop */ static void stm32_stop_tx(struct uart_port *port) { - stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE); + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); } /* There are probably characters waiting to be transmitted. */ @@ -282,33 +397,40 @@ static void stm32_start_tx(struct uart_port *port) if (uart_circ_empty(xmit)) return; - stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE); + stm32_transmit_chars(port); } /* Throttle the remote when input buffer is about to overflow. */ static void stm32_throttle(struct uart_port *port) { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long flags; spin_lock_irqsave(&port->lock, flags); - stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE); + stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE); spin_unlock_irqrestore(&port->lock, flags); } /* Unthrottle the remote, the input buffer can now accept data. */ static void stm32_unthrottle(struct uart_port *port) { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long flags; spin_lock_irqsave(&port->lock, flags); - stm32_set_bits(port, USART_CR1, USART_CR1_RXNEIE); + stm32_set_bits(port, ofs->cr1, USART_CR1_RXNEIE); spin_unlock_irqrestore(&port->lock, flags); } /* Receive stop */ static void stm32_stop_rx(struct uart_port *port) { - stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE); + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE); } /* Handle breaks - ignored by us */ @@ -318,26 +440,34 @@ static void stm32_break_ctl(struct uart_port *port, int break_state) static int stm32_startup(struct uart_port *port) { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; const char *name = to_platform_device(port->dev)->name; u32 val; int ret; - ret = request_irq(port->irq, stm32_interrupt, 0, name, port); + ret = request_threaded_irq(port->irq, stm32_interrupt, + stm32_threaded_interrupt, + IRQF_NO_SUSPEND, name, port); if (ret) return ret; val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; - stm32_set_bits(port, USART_CR1, val); + stm32_set_bits(port, ofs->cr1, val); return 0; } static void stm32_shutdown(struct uart_port *port) { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct stm32_usart_config *cfg = &stm32_port->info->cfg; u32 val; val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; - stm32_set_bits(port, USART_CR1, val); + val |= BIT(cfg->uart_enable_bit); + stm32_clr_bits(port, ofs->cr1, val); free_irq(port->irq, port); } @@ -346,6 +476,8 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct stm32_usart_config *cfg = &stm32_port->info->cfg; unsigned int baud; u32 usartdiv, mantissa, fraction, oversampling; tcflag_t cflag = termios->c_cflag; @@ -360,9 +492,10 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, spin_lock_irqsave(&port->lock, flags); /* Stop serial port and reset value */ - writel_relaxed(0, port->membase + USART_CR1); + writel_relaxed(0, port->membase + ofs->cr1); - cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE; + cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; + cr1 |= BIT(cfg->uart_enable_bit); cr2 = 0; cr3 = 0; @@ -371,8 +504,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, if (cflag & PARENB) { cr1 |= USART_CR1_PCE; - if ((cflag & CSIZE) == CS8) - cr1 |= USART_CR1_M; + if ((cflag & CSIZE) == CS8) { + if (cfg->has_7bits_data) + cr1 |= USART_CR1_M0; + else + cr1 |= USART_CR1_M; + } } if (cflag & PARODD) @@ -394,15 +531,15 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, */ if (usartdiv < 16) { oversampling = 8; - stm32_set_bits(port, USART_CR1, USART_CR1_OVER8); + stm32_set_bits(port, ofs->cr1, USART_CR1_OVER8); } else { oversampling = 16; - stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8); + stm32_clr_bits(port, ofs->cr1, USART_CR1_OVER8); } mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; fraction = usartdiv % oversampling; - writel_relaxed(mantissa | fraction, port->membase + USART_BRR); + writel_relaxed(mantissa | fraction, port->membase + ofs->brr); uart_update_timeout(port, cflag, baud); @@ -430,9 +567,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= USART_SR_DUMMY_RX; - writel_relaxed(cr3, port->membase + USART_CR3); - writel_relaxed(cr2, port->membase + USART_CR2); - writel_relaxed(cr1, port->membase + USART_CR1); + if (stm32_port->rx_ch) + cr3 |= USART_CR3_DMAR; + + writel_relaxed(cr3, port->membase + ofs->cr3); + writel_relaxed(cr2, port->membase + ofs->cr2); + writel_relaxed(cr1, port->membase + ofs->cr1); spin_unlock_irqrestore(&port->lock, flags); } @@ -469,6 +609,8 @@ static void stm32_pm(struct uart_port *port, unsigned int state, { struct stm32_port *stm32port = container_of(port, struct stm32_port, port); + struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + struct stm32_usart_config *cfg = &stm32port->info->cfg; unsigned long flags = 0; switch (state) { @@ -477,7 +619,7 @@ static void stm32_pm(struct uart_port *port, unsigned int state, break; case UART_PM_STATE_OFF: spin_lock_irqsave(&port->lock, flags); - stm32_clr_bits(port, USART_CR1, USART_CR1_UE); + stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); spin_unlock_irqrestore(&port->lock, flags); clk_disable_unprepare(stm32port->clk); break; @@ -539,8 +681,6 @@ static int stm32_init_port(struct stm32_port *stm32port, if (!stm32port->port.uartclk) ret = -EINVAL; - clk_disable_unprepare(stm32port->clk); - return ret; } @@ -560,30 +700,162 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) return NULL; stm32_ports[id].hw_flow_control = of_property_read_bool(np, - "auto-flow-control"); + "st,hw-flow-ctrl"); stm32_ports[id].port.line = id; return &stm32_ports[id]; } #ifdef CONFIG_OF static const struct of_device_id stm32_match[] = { - { .compatible = "st,stm32-usart", }, - { .compatible = "st,stm32-uart", }, + { .compatible = "st,stm32-usart", .data = &stm32f4_info}, + { .compatible = "st,stm32-uart", .data = &stm32f4_info}, + { .compatible = "st,stm32f7-usart", .data = &stm32f7_info}, + { .compatible = "st,stm32f7-uart", .data = &stm32f7_info}, {}, }; MODULE_DEVICE_TABLE(of, stm32_match); #endif -static int stm32_serial_probe(struct platform_device *pdev) +static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, + struct platform_device *pdev) { + struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + struct uart_port *port = &stm32port->port; + struct device *dev = &pdev->dev; + struct dma_slave_config config; + struct dma_async_tx_descriptor *desc = NULL; + dma_cookie_t cookie; int ret; + + /* Request DMA RX channel */ + stm32port->rx_ch = dma_request_slave_channel(dev, "rx"); + if (!stm32port->rx_ch) { + dev_info(dev, "rx dma alloc failed\n"); + return -ENODEV; + } + stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L, + &stm32port->rx_dma_buf, + GFP_KERNEL); + if (!stm32port->rx_buf) { + ret = -ENOMEM; + goto alloc_err; + } + + /* Configure DMA channel */ + memset(&config, 0, sizeof(config)); + config.src_addr = port->mapbase + ofs->rdr; + config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + + ret = dmaengine_slave_config(stm32port->rx_ch, &config); + if (ret < 0) { + dev_err(dev, "rx dma channel config failed\n"); + ret = -ENODEV; + goto config_err; + } + + /* Prepare a DMA cyclic transaction */ + desc = dmaengine_prep_dma_cyclic(stm32port->rx_ch, + stm32port->rx_dma_buf, + RX_BUF_L, RX_BUF_P, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(dev, "rx dma prep cyclic failed\n"); + ret = -ENODEV; + goto config_err; + } + + /* No callback as dma buffer is drained on usart interrupt */ + desc->callback = NULL; + desc->callback_param = NULL; + + /* Push current DMA transaction in the pending queue */ + cookie = dmaengine_submit(desc); + + /* Issue pending DMA requests */ + dma_async_issue_pending(stm32port->rx_ch); + + return 0; + +config_err: + dma_free_coherent(&pdev->dev, + RX_BUF_L, stm32port->rx_buf, + stm32port->rx_dma_buf); + +alloc_err: + dma_release_channel(stm32port->rx_ch); + stm32port->rx_ch = NULL; + + return ret; +} + +static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, + struct platform_device *pdev) +{ + struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + struct uart_port *port = &stm32port->port; + struct device *dev = &pdev->dev; + struct dma_slave_config config; + int ret; + + stm32port->tx_dma_busy = false; + + /* Request DMA TX channel */ + stm32port->tx_ch = dma_request_slave_channel(dev, "tx"); + if (!stm32port->tx_ch) { + dev_info(dev, "tx dma alloc failed\n"); + return -ENODEV; + } + stm32port->tx_buf = dma_alloc_coherent(&pdev->dev, TX_BUF_L, + &stm32port->tx_dma_buf, + GFP_KERNEL); + if (!stm32port->tx_buf) { + ret = -ENOMEM; + goto alloc_err; + } + + /* Configure DMA channel */ + memset(&config, 0, sizeof(config)); + config.dst_addr = port->mapbase + ofs->tdr; + config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + + ret = dmaengine_slave_config(stm32port->tx_ch, &config); + if (ret < 0) { + dev_err(dev, "tx dma channel config failed\n"); + ret = -ENODEV; + goto config_err; + } + + return 0; + +config_err: + dma_free_coherent(&pdev->dev, + TX_BUF_L, stm32port->tx_buf, + stm32port->tx_dma_buf); + +alloc_err: + dma_release_channel(stm32port->tx_ch); + stm32port->tx_ch = NULL; + + return ret; +} + +static int stm32_serial_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; struct stm32_port *stm32port; + int ret; stm32port = stm32_of_get_stm32_port(pdev); if (!stm32port) return -ENODEV; + match = of_match_device(stm32_match, &pdev->dev); + if (match && match->data) + stm32port->info = (struct stm32_usart_info *)match->data; + else + return -EINVAL; + ret = stm32_init_port(stm32port, pdev); if (ret) return ret; @@ -592,6 +864,14 @@ static int stm32_serial_probe(struct platform_device *pdev) if (ret) return ret; + ret = stm32_of_dma_rx_probe(stm32port, pdev); + if (ret) + dev_info(&pdev->dev, "interrupt mode used for rx (no dma)\n"); + + ret = stm32_of_dma_tx_probe(stm32port, pdev); + if (ret) + dev_info(&pdev->dev, "interrupt mode used for tx (no dma)\n"); + platform_set_drvdata(pdev, &stm32port->port); return 0; @@ -600,6 +880,30 @@ static int stm32_serial_probe(struct platform_device *pdev) static int stm32_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + + if (stm32_port->rx_ch) + dma_release_channel(stm32_port->rx_ch); + + if (stm32_port->rx_dma_buf) + dma_free_coherent(&pdev->dev, + RX_BUF_L, stm32_port->rx_buf, + stm32_port->rx_dma_buf); + + stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + + if (stm32_port->tx_ch) + dma_release_channel(stm32_port->tx_ch); + + if (stm32_port->tx_dma_buf) + dma_free_coherent(&pdev->dev, + TX_BUF_L, stm32_port->tx_buf, + stm32_port->tx_dma_buf); + + clk_disable_unprepare(stm32_port->clk); return uart_remove_one_port(&stm32_usart_driver, port); } @@ -608,15 +912,21 @@ static int stm32_serial_remove(struct platform_device *pdev) #ifdef CONFIG_SERIAL_STM32_CONSOLE static void stm32_console_putchar(struct uart_port *port, int ch) { - while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE)) + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + while (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE)) cpu_relax(); - writel_relaxed(ch, port->membase + USART_DR); + writel_relaxed(ch, port->membase + ofs->tdr); } static void stm32_console_write(struct console *co, const char *s, unsigned cnt) { struct uart_port *port = &stm32_ports[co->index].port; + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct stm32_usart_config *cfg = &stm32_port->info->cfg; unsigned long flags; u32 old_cr1, new_cr1; int locked = 1; @@ -629,15 +939,16 @@ static void stm32_console_write(struct console *co, const char *s, unsigned cnt) else spin_lock(&port->lock); - /* Save and disable interrupts */ - old_cr1 = readl_relaxed(port->membase + USART_CR1); + /* Save and disable interrupts, enable the transmitter */ + old_cr1 = readl_relaxed(port->membase + ofs->cr1); new_cr1 = old_cr1 & ~USART_CR1_IE_MASK; - writel_relaxed(new_cr1, port->membase + USART_CR1); + new_cr1 |= USART_CR1_TE | BIT(cfg->uart_enable_bit); + writel_relaxed(new_cr1, port->membase + ofs->cr1); uart_console_write(port, s, cnt, stm32_console_putchar); /* Restore interrupt state */ - writel_relaxed(old_cr1, port->membase + USART_CR1); + writel_relaxed(old_cr1, port->membase + ofs->cr1); if (locked) spin_unlock(&port->lock); diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h new file mode 100644 index 000000000000..41d974923102 --- /dev/null +++ b/drivers/tty/serial/stm32-usart.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) Maxime Coquelin 2015 + * Authors: Maxime Coquelin <mcoquelin.stm32@gmail.com> + * Gerald Baeza <gerald_baeza@yahoo.fr> + * License terms: GNU General Public License (GPL), version 2 + */ + +#define DRIVER_NAME "stm32-usart" + +struct stm32_usart_offsets { + u8 cr1; + u8 cr2; + u8 cr3; + u8 brr; + u8 gtpr; + u8 rtor; + u8 rqr; + u8 isr; + u8 icr; + u8 rdr; + u8 tdr; +}; + +struct stm32_usart_config { + u8 uart_enable_bit; /* USART_CR1_UE */ + bool has_7bits_data; +}; + +struct stm32_usart_info { + struct stm32_usart_offsets ofs; + struct stm32_usart_config cfg; +}; + +#define UNDEF_REG ~0 + +/* Register offsets */ +struct stm32_usart_info stm32f4_info = { + .ofs = { + .isr = 0x00, + .rdr = 0x04, + .tdr = 0x04, + .brr = 0x08, + .cr1 = 0x0c, + .cr2 = 0x10, + .cr3 = 0x14, + .gtpr = 0x18, + .rtor = UNDEF_REG, + .rqr = UNDEF_REG, + .icr = UNDEF_REG, + }, + .cfg = { + .uart_enable_bit = 13, + .has_7bits_data = false, + } +}; + +struct stm32_usart_info stm32f7_info = { + .ofs = { + .cr1 = 0x00, + .cr2 = 0x04, + .cr3 = 0x08, + .brr = 0x0c, + .gtpr = 0x10, + .rtor = 0x14, + .rqr = 0x18, + .isr = 0x1c, + .icr = 0x20, + .rdr = 0x24, + .tdr = 0x28, + }, + .cfg = { + .uart_enable_bit = 0, + .has_7bits_data = true, + } +}; + +/* USART_SR (F4) / USART_ISR (F7) */ +#define USART_SR_PE BIT(0) +#define USART_SR_FE BIT(1) +#define USART_SR_NF BIT(2) +#define USART_SR_ORE BIT(3) +#define USART_SR_IDLE BIT(4) +#define USART_SR_RXNE BIT(5) +#define USART_SR_TC BIT(6) +#define USART_SR_TXE BIT(7) +#define USART_SR_LBD BIT(8) +#define USART_SR_CTSIF BIT(9) +#define USART_SR_CTS BIT(10) /* F7 */ +#define USART_SR_RTOF BIT(11) /* F7 */ +#define USART_SR_EOBF BIT(12) /* F7 */ +#define USART_SR_ABRE BIT(14) /* F7 */ +#define USART_SR_ABRF BIT(15) /* F7 */ +#define USART_SR_BUSY BIT(16) /* F7 */ +#define USART_SR_CMF BIT(17) /* F7 */ +#define USART_SR_SBKF BIT(18) /* F7 */ +#define USART_SR_TEACK BIT(21) /* F7 */ +#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \ + USART_SR_FE | USART_SR_PE) +/* Dummy bits */ +#define USART_SR_DUMMY_RX BIT(16) + +/* USART_ICR (F7) */ +#define USART_CR_TC BIT(6) + +/* USART_DR */ +#define USART_DR_MASK GENMASK(8, 0) + +/* USART_BRR */ +#define USART_BRR_DIV_F_MASK GENMASK(3, 0) +#define USART_BRR_DIV_M_MASK GENMASK(15, 4) +#define USART_BRR_DIV_M_SHIFT 4 + +/* USART_CR1 */ +#define USART_CR1_SBK BIT(0) +#define USART_CR1_RWU BIT(1) /* F4 */ +#define USART_CR1_RE BIT(2) +#define USART_CR1_TE BIT(3) +#define USART_CR1_IDLEIE BIT(4) +#define USART_CR1_RXNEIE BIT(5) +#define USART_CR1_TCIE BIT(6) +#define USART_CR1_TXEIE BIT(7) +#define USART_CR1_PEIE BIT(8) +#define USART_CR1_PS BIT(9) +#define USART_CR1_PCE BIT(10) +#define USART_CR1_WAKE BIT(11) +#define USART_CR1_M BIT(12) +#define USART_CR1_M0 BIT(12) /* F7 */ +#define USART_CR1_MME BIT(13) /* F7 */ +#define USART_CR1_CMIE BIT(14) /* F7 */ +#define USART_CR1_OVER8 BIT(15) +#define USART_CR1_DEDT_MASK GENMASK(20, 16) /* F7 */ +#define USART_CR1_DEAT_MASK GENMASK(25, 21) /* F7 */ +#define USART_CR1_RTOIE BIT(26) /* F7 */ +#define USART_CR1_EOBIE BIT(27) /* F7 */ +#define USART_CR1_M1 BIT(28) /* F7 */ +#define USART_CR1_IE_MASK (GENMASK(8, 4) | BIT(14) | BIT(26) | BIT(27)) + +/* USART_CR2 */ +#define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */ +#define USART_CR2_ADDM7 BIT(4) /* F7 */ +#define USART_CR2_LBDL BIT(5) +#define USART_CR2_LBDIE BIT(6) +#define USART_CR2_LBCL BIT(8) +#define USART_CR2_CPHA BIT(9) +#define USART_CR2_CPOL BIT(10) +#define USART_CR2_CLKEN BIT(11) +#define USART_CR2_STOP_2B BIT(13) +#define USART_CR2_STOP_MASK GENMASK(13, 12) +#define USART_CR2_LINEN BIT(14) +#define USART_CR2_SWAP BIT(15) /* F7 */ +#define USART_CR2_RXINV BIT(16) /* F7 */ +#define USART_CR2_TXINV BIT(17) /* F7 */ +#define USART_CR2_DATAINV BIT(18) /* F7 */ +#define USART_CR2_MSBFIRST BIT(19) /* F7 */ +#define USART_CR2_ABREN BIT(20) /* F7 */ +#define USART_CR2_ABRMOD_MASK GENMASK(22, 21) /* F7 */ +#define USART_CR2_RTOEN BIT(23) /* F7 */ +#define USART_CR2_ADD_F7_MASK GENMASK(31, 24) /* F7 */ + +/* USART_CR3 */ +#define USART_CR3_EIE BIT(0) +#define USART_CR3_IREN BIT(1) +#define USART_CR3_IRLP BIT(2) +#define USART_CR3_HDSEL BIT(3) +#define USART_CR3_NACK BIT(4) +#define USART_CR3_SCEN BIT(5) +#define USART_CR3_DMAR BIT(6) +#define USART_CR3_DMAT BIT(7) +#define USART_CR3_RTSE BIT(8) +#define USART_CR3_CTSE BIT(9) +#define USART_CR3_CTSIE BIT(10) +#define USART_CR3_ONEBIT BIT(11) +#define USART_CR3_OVRDIS BIT(12) /* F7 */ +#define USART_CR3_DDRE BIT(13) /* F7 */ +#define USART_CR3_DEM BIT(14) /* F7 */ +#define USART_CR3_DEP BIT(15) /* F7 */ +#define USART_CR3_SCARCNT_MASK GENMASK(19, 17) /* F7 */ + +/* USART_GTPR */ +#define USART_GTPR_PSC_MASK GENMASK(7, 0) +#define USART_GTPR_GT_MASK GENMASK(15, 8) + +/* USART_RTOR */ +#define USART_RTOR_RTO_MASK GENMASK(23, 0) /* F7 */ +#define USART_RTOR_BLEN_MASK GENMASK(31, 24) /* F7 */ + +/* USART_RQR */ +#define USART_RQR_ABRRQ BIT(0) /* F7 */ +#define USART_RQR_SBKRQ BIT(1) /* F7 */ +#define USART_RQR_MMRQ BIT(2) /* F7 */ +#define USART_RQR_RXFRQ BIT(3) /* F7 */ +#define USART_RQR_TXFRQ BIT(4) /* F7 */ + +/* USART_ICR */ +#define USART_ICR_PECF BIT(0) /* F7 */ +#define USART_ICR_FFECF BIT(1) /* F7 */ +#define USART_ICR_NCF BIT(2) /* F7 */ +#define USART_ICR_ORECF BIT(3) /* F7 */ +#define USART_ICR_IDLECF BIT(4) /* F7 */ +#define USART_ICR_TCCF BIT(6) /* F7 */ +#define USART_ICR_LBDCF BIT(8) /* F7 */ +#define USART_ICR_CTSCF BIT(9) /* F7 */ +#define USART_ICR_RTOCF BIT(11) /* F7 */ +#define USART_ICR_EOBCF BIT(12) /* F7 */ +#define USART_ICR_CMCF BIT(17) /* F7 */ + +#define STM32_SERIAL_NAME "ttyS" +#define STM32_MAX_PORTS 6 + +#define RX_BUF_L 200 /* dma rx buffer length */ +#define RX_BUF_P RX_BUF_L /* dma rx buffer period */ +#define TX_BUF_L 200 /* dma tx buffer length */ + +struct stm32_port { + struct uart_port port; + struct clk *clk; + struct stm32_usart_info *info; + struct dma_chan *rx_ch; /* dma rx channel */ + dma_addr_t rx_dma_buf; /* dma rx buffer bus address */ + unsigned char *rx_buf; /* dma rx buffer cpu address */ + struct dma_chan *tx_ch; /* dma tx channel */ + dma_addr_t tx_dma_buf; /* dma tx buffer bus address */ + unsigned char *tx_buf; /* dma tx buffer cpu address */ + bool tx_dma_busy; /* dma tx busy */ + bool hw_flow_control; +}; + +static struct stm32_port stm32_ports[STM32_MAX_PORTS]; +static struct uart_driver stm32_usart_driver; diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c index 512c162634a3..5da7fe40e391 100644 --- a/drivers/tty/serial/timbuart.c +++ b/drivers/tty/serial/timbuart.c @@ -394,7 +394,7 @@ static int timbuart_verify_port(struct uart_port *port, return -EINVAL; } -static struct uart_ops timbuart_ops = { +static const struct uart_ops timbuart_ops = { .tx_empty = timbuart_tx_empty, .set_mctrl = timbuart_set_mctrl, .get_mctrl = timbuart_get_mctrl, diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 05089b6c2f30..817bb0d3f326 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -387,7 +387,7 @@ static void ulite_put_poll_char(struct uart_port *port, unsigned char ch) } #endif -static struct uart_ops ulite_ops = { +static const struct uart_ops ulite_ops = { .tx_empty = ulite_tx_empty, .set_mctrl = ulite_set_mctrl, .get_mctrl = ulite_get_mctrl, diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 23cfc5e16b45..6b85adce0ac9 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -118,7 +118,7 @@ struct vt8500_port { * have been allocated as we can't use pdev->id in * devicetree */ -static unsigned long vt8500_ports_in_use; +static DECLARE_BITMAP(vt8500_ports_in_use, VT8500_MAX_PORTS); static inline void vt8500_write(struct uart_port *port, unsigned int val, unsigned int off) @@ -663,15 +663,15 @@ static int vt8500_serial_probe(struct platform_device *pdev) if (port < 0) { /* calculate the port id */ - port = find_first_zero_bit(&vt8500_ports_in_use, - sizeof(vt8500_ports_in_use)); + port = find_first_zero_bit(vt8500_ports_in_use, + VT8500_MAX_PORTS); } if (port >= VT8500_MAX_PORTS) return -ENODEV; /* reserve the port id */ - if (test_and_set_bit(port, &vt8500_ports_in_use)) { + if (test_and_set_bit(port, vt8500_ports_in_use)) { /* port already in use - shouldn't really happen */ return -EBUSY; } diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 9ca1a4d1b66a..f37edaa5ac75 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -57,7 +57,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); #define CDNS_UART_IMR 0x10 /* Interrupt Mask */ #define CDNS_UART_ISR 0x14 /* Interrupt Status */ #define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */ -#define CDNS_UART_RXTOUT 0x1C /* RX Timeout */ +#define CDNS_UART_RXTOUT 0x1C /* RX Timeout */ #define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */ #define CDNS_UART_MODEMCR 0x24 /* Modem Control */ #define CDNS_UART_MODEMSR 0x28 /* Modem Status */ @@ -68,6 +68,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); #define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */ #define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */ #define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */ +#define CDNS_UART_RXBS 0x48 /* RX FIFO byte status register */ /* Control Register Bit Definitions */ #define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */ @@ -79,6 +80,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); #define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */ #define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */ #define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */ +#define CDNS_UART_RXBS_PARITY 0x00000001 /* Parity error status */ +#define CDNS_UART_RXBS_FRAMING 0x00000002 /* Framing error status */ +#define CDNS_UART_RXBS_BRK 0x00000004 /* Overrun error status */ /* * Mode Register: @@ -126,13 +130,27 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); #define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */ #define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */ -#define CDNS_UART_RX_IRQS (CDNS_UART_IXR_PARITY | CDNS_UART_IXR_FRAMING | \ - CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_RXTRIG | \ + /* + * Do not enable parity error interrupt for the following + * reason: When parity error interrupt is enabled, each Rx + * parity error always results in 2 events. The first one + * being parity error interrupt and the second one with a + * proper Rx interrupt with the incoming data. Disabling + * parity error interrupt ensures better handling of parity + * error events. With this change, for a parity error case, we + * get a Rx interrupt with parity error set in ISR register + * and we still handle parity errors in the desired way. + */ + +#define CDNS_UART_RX_IRQS (CDNS_UART_IXR_FRAMING | \ + CDNS_UART_IXR_OVERRUN | \ + CDNS_UART_IXR_RXTRIG | \ CDNS_UART_IXR_TOUT) /* Goes in read_status_mask for break detection as the HW doesn't do it*/ -#define CDNS_UART_IXR_BRK 0x80000000 +#define CDNS_UART_IXR_BRK 0x00002000 +#define CDNS_UART_RXBS_SUPPORT BIT(1) /* * Modem Control register: * The read/write Modem Control register controls the interface with the modem @@ -172,46 +190,66 @@ struct cdns_uart { struct clk *pclk; unsigned int baud; struct notifier_block clk_rate_change_nb; + u32 quirks; +}; +struct cdns_platform_data { + u32 quirks; }; #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \ clk_rate_change_nb); -static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus) +/** + * cdns_uart_handle_rx - Handle the received bytes along with Rx errors. + * @dev_id: Id of the UART port + * @isrstatus: The interrupt status register value as read + * Return: None + */ +static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus) { - /* - * There is no hardware break detection, so we interpret framing - * error with all-zeros data as a break sequence. Most of the time, - * there's another non-zero byte at the end of the sequence. - */ - if (isrstatus & CDNS_UART_IXR_FRAMING) { - while (!(readl(port->membase + CDNS_UART_SR) & - CDNS_UART_SR_RXEMPTY)) { - if (!readl(port->membase + CDNS_UART_FIFO)) { + struct uart_port *port = (struct uart_port *)dev_id; + struct cdns_uart *cdns_uart = port->private_data; + unsigned int data; + unsigned int rxbs_status = 0; + unsigned int status_mask; + unsigned int framerrprocessed = 0; + char status = TTY_NORMAL; + bool is_rxbs_support; + + is_rxbs_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT; + + while ((readl(port->membase + CDNS_UART_SR) & + CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) { + if (is_rxbs_support) + rxbs_status = readl(port->membase + CDNS_UART_RXBS); + data = readl(port->membase + CDNS_UART_FIFO); + port->icount.rx++; + /* + * There is no hardware break detection in Zynq, so we interpret + * framing error with all-zeros data as a break sequence. + * Most of the time, there's another non-zero byte at the + * end of the sequence. + */ + if (!is_rxbs_support && (isrstatus & CDNS_UART_IXR_FRAMING)) { + if (!data) { port->read_status_mask |= CDNS_UART_IXR_BRK; - isrstatus &= ~CDNS_UART_IXR_FRAMING; + framerrprocessed = 1; + continue; } } - writel(CDNS_UART_IXR_FRAMING, port->membase + CDNS_UART_ISR); - } - - /* drop byte with parity error if IGNPAR specified */ - if (isrstatus & port->ignore_status_mask & CDNS_UART_IXR_PARITY) - isrstatus &= ~(CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT); - - isrstatus &= port->read_status_mask; - isrstatus &= ~port->ignore_status_mask; - - if (!(isrstatus & (CDNS_UART_IXR_TOUT | CDNS_UART_IXR_RXTRIG))) - return; - - while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)) { - u32 data; - char status = TTY_NORMAL; + if (is_rxbs_support && (rxbs_status & CDNS_UART_RXBS_BRK)) { + port->icount.brk++; + status = TTY_BREAK; + if (uart_handle_break(port)) + continue; + } - data = readl(port->membase + CDNS_UART_FIFO); + isrstatus &= port->read_status_mask; + isrstatus &= ~port->ignore_status_mask; + status_mask = port->read_status_mask; + status_mask &= ~port->ignore_status_mask; - /* Non-NULL byte after BREAK is garbage (99%) */ - if (data && (port->read_status_mask & CDNS_UART_IXR_BRK)) { + if (data && + (port->read_status_mask & CDNS_UART_IXR_BRK)) { port->read_status_mask &= ~CDNS_UART_IXR_BRK; port->icount.brk++; if (uart_handle_break(port)) @@ -221,57 +259,83 @@ static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus) if (uart_handle_sysrq_char(port, data)) continue; - port->icount.rx++; - - if (isrstatus & CDNS_UART_IXR_PARITY) { - port->icount.parity++; - status = TTY_PARITY; - } else if (isrstatus & CDNS_UART_IXR_FRAMING) { - port->icount.frame++; - status = TTY_FRAME; - } else if (isrstatus & CDNS_UART_IXR_OVERRUN) { + if (is_rxbs_support) { + if ((rxbs_status & CDNS_UART_RXBS_PARITY) + && (status_mask & CDNS_UART_IXR_PARITY)) { + port->icount.parity++; + status = TTY_PARITY; + } + if ((rxbs_status & CDNS_UART_RXBS_FRAMING) + && (status_mask & CDNS_UART_IXR_PARITY)) { + port->icount.frame++; + status = TTY_FRAME; + } + } else { + if (isrstatus & CDNS_UART_IXR_PARITY) { + port->icount.parity++; + status = TTY_PARITY; + } + if ((isrstatus & CDNS_UART_IXR_FRAMING) && + !framerrprocessed) { + port->icount.frame++; + status = TTY_FRAME; + } + } + if (isrstatus & CDNS_UART_IXR_OVERRUN) { port->icount.overrun++; + tty_insert_flip_char(&port->state->port, 0, + TTY_OVERRUN); } - - uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN, - data, status); + tty_insert_flip_char(&port->state->port, data, status); + isrstatus = 0; } + spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); + spin_lock(&port->lock); } -static void cdns_uart_handle_tx(struct uart_port *port) +/** + * cdns_uart_handle_tx - Handle the bytes to be Txed. + * @dev_id: Id of the UART port + * Return: None + */ +static void cdns_uart_handle_tx(void *dev_id) { + struct uart_port *port = (struct uart_port *)dev_id; unsigned int numbytes; if (uart_circ_empty(&port->state->xmit)) { writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR); - return; - } - - numbytes = port->fifosize; - while (numbytes && !uart_circ_empty(&port->state->xmit) && - !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) { - /* - * Get the data from the UART circular buffer - * and write it to the cdns_uart's TX_FIFO - * register. - */ - writel(port->state->xmit.buf[port->state->xmit.tail], - port->membase + CDNS_UART_FIFO); - port->icount.tx++; - - /* - * Adjust the tail of the UART buffer and wrap - * the buffer if it reaches limit. - */ - port->state->xmit.tail = - (port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1); + } else { + numbytes = port->fifosize; + while (numbytes && !uart_circ_empty(&port->state->xmit) && + !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) { + /* + * Get the data from the UART circular buffer + * and write it to the cdns_uart's TX_FIFO + * register. + */ + writel( + port->state->xmit.buf[port->state->xmit. + tail], port->membase + CDNS_UART_FIFO); + + port->icount.tx++; + + /* + * Adjust the tail of the UART buffer and wrap + * the buffer if it reaches limit. + */ + port->state->xmit.tail = + (port->state->xmit.tail + 1) & + (UART_XMIT_SIZE - 1); + + numbytes--; + } - numbytes--; + if (uart_circ_chars_pending( + &port->state->xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); } - - if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); } /** @@ -284,27 +348,24 @@ static void cdns_uart_handle_tx(struct uart_port *port) static irqreturn_t cdns_uart_isr(int irq, void *dev_id) { struct uart_port *port = (struct uart_port *)dev_id; - unsigned long flags; unsigned int isrstatus; - spin_lock_irqsave(&port->lock, flags); + spin_lock(&port->lock); /* Read the interrupt status register to determine which - * interrupt(s) is/are active. + * interrupt(s) is/are active and clear them. */ isrstatus = readl(port->membase + CDNS_UART_ISR); - - if (isrstatus & CDNS_UART_RX_IRQS) - cdns_uart_handle_rx(port, isrstatus); - - if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY) - cdns_uart_handle_tx(port); - writel(isrstatus, port->membase + CDNS_UART_ISR); - /* be sure to release the lock and tty before leaving */ - spin_unlock_irqrestore(&port->lock, flags); + if (isrstatus & CDNS_UART_IXR_TXEMPTY) { + cdns_uart_handle_tx(dev_id); + isrstatus &= ~CDNS_UART_IXR_TXEMPTY; + } + if (isrstatus & CDNS_UART_IXR_MASK) + cdns_uart_handle_rx(dev_id, isrstatus); + spin_unlock(&port->lock); return IRQ_HANDLED; } @@ -653,6 +714,10 @@ static void cdns_uart_set_termios(struct uart_port *port, ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; writel(ctrl_reg, port->membase + CDNS_UART_CR); + while (readl(port->membase + CDNS_UART_CR) & + (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) + cpu_relax(); + /* * Clear the RX disable and TX disable bits and then set the TX enable * bit and RX enable bit to enable the transmitter and receiver. @@ -736,10 +801,14 @@ static void cdns_uart_set_termios(struct uart_port *port, */ static int cdns_uart_startup(struct uart_port *port) { + struct cdns_uart *cdns_uart = port->private_data; + bool is_brk_support; int ret; unsigned long flags; unsigned int status = 0; + is_brk_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT; + spin_lock_irqsave(&port->lock, flags); /* Disable the TX and RX */ @@ -752,6 +821,10 @@ static int cdns_uart_startup(struct uart_port *port) writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST, port->membase + CDNS_UART_CR); + while (readl(port->membase + CDNS_UART_CR) & + (CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST)) + cpu_relax(); + /* * Clear the RX disable bit and then set the RX enable bit to enable * the receiver. @@ -794,7 +867,11 @@ static int cdns_uart_startup(struct uart_port *port) } /* Set the Interrupt Registers with desired interrupts */ - writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER); + if (is_brk_support) + writel(CDNS_UART_RX_IRQS | CDNS_UART_IXR_BRK, + port->membase + CDNS_UART_IER); + else + writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER); return 0; } @@ -993,7 +1070,7 @@ static void cdns_uart_pm(struct uart_port *port, unsigned int state, } } -static struct uart_ops cdns_uart_ops = { +static const struct uart_ops cdns_uart_ops = { .set_mctrl = cdns_uart_set_mctrl, .get_mctrl = cdns_uart_get_mctrl, .start_tx = cdns_uart_start_tx, @@ -1088,9 +1165,34 @@ static void __init cdns_early_write(struct console *con, const char *s, static int __init cdns_early_console_setup(struct earlycon_device *device, const char *opt) { - if (!device->port.membase) + struct uart_port *port = &device->port; + + if (!port->membase) return -ENODEV; + /* initialise control register */ + writel(CDNS_UART_CR_TX_EN|CDNS_UART_CR_TXRST|CDNS_UART_CR_RXRST, + port->membase + CDNS_UART_CR); + + /* only set baud if specified on command line - otherwise + * assume it has been initialized by a boot loader. + */ + if (device->baud) { + u32 cd = 0, bdiv = 0; + u32 mr; + int div8; + + cdns_uart_calc_baud_divs(port->uartclk, device->baud, + &bdiv, &cd, &div8); + mr = CDNS_UART_MR_PARITY_NONE; + if (div8) + mr |= CDNS_UART_MR_CLKSEL; + + writel(mr, port->membase + CDNS_UART_MR); + writel(cd, port->membase + CDNS_UART_BAUDGEN); + writel(bdiv, port->membase + CDNS_UART_BAUDDIV); + } + device->con->write = cdns_early_write; return 0; @@ -1328,6 +1430,18 @@ static int cdns_uart_resume(struct device *device) static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend, cdns_uart_resume); +static const struct cdns_platform_data zynqmp_uart_def = { + .quirks = CDNS_UART_RXBS_SUPPORT, }; + +/* Match table for of_platform binding */ +static const struct of_device_id cdns_uart_of_match[] = { + { .compatible = "xlnx,xuartps", }, + { .compatible = "cdns,uart-r1p8", }, + { .compatible = "cdns,uart-r1p12", .data = &zynqmp_uart_def }, + {} +}; +MODULE_DEVICE_TABLE(of, cdns_uart_of_match); + /** * cdns_uart_probe - Platform driver probe * @pdev: Pointer to the platform device structure @@ -1340,12 +1454,20 @@ static int cdns_uart_probe(struct platform_device *pdev) struct uart_port *port; struct resource *res; struct cdns_uart *cdns_uart_data; + const struct of_device_id *match; cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data), GFP_KERNEL); if (!cdns_uart_data) return -ENOMEM; + match = of_match_node(cdns_uart_of_match, pdev->dev.of_node); + if (match && match->data) { + const struct cdns_platform_data *data = match->data; + + cdns_uart_data->quirks = data->quirks; + } + cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(cdns_uart_data->pclk)) { cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk"); @@ -1471,14 +1593,6 @@ static int cdns_uart_remove(struct platform_device *pdev) return rc; } -/* Match table for of_platform binding */ -static const struct of_device_id cdns_uart_of_match[] = { - { .compatible = "xlnx,xuartps", }, - { .compatible = "cdns,uart-r1p8", }, - {} -}; -MODULE_DEVICE_TABLE(of, cdns_uart_of_match); - static struct platform_driver cdns_uart_platform_driver = { .probe = cdns_uart_probe, .remove = cdns_uart_remove, diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 2705ca960e92..e841a4e0e726 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1312,12 +1312,12 @@ static int vc_t416_color(struct vc_data *vc, int i, if (i > vc->vc_npar) return i; - if (vc->vc_par[i] == 5 && i < vc->vc_npar) { - /* 256 colours -- ubiquitous */ + if (vc->vc_par[i] == 5 && i + 1 <= vc->vc_npar) { + /* 256 colours */ i++; rgb_from_256(vc->vc_par[i], &c); - } else if (vc->vc_par[i] == 2 && i <= vc->vc_npar + 3) { - /* 24 bit -- extremely rare */ + } else if (vc->vc_par[i] == 2 && i + 3 <= vc->vc_npar) { + /* 24 bit */ c.r = vc->vc_par[i + 1]; c.g = vc->vc_par[i + 2]; c.b = vc->vc_par[i + 3]; @@ -1415,6 +1415,11 @@ static void csi_m(struct vc_data *vc) (vc->vc_color & 0x0f); break; default: + if (vc->vc_par[i] >= 90 && vc->vc_par[i] <= 107) { + if (vc->vc_par[i] < 100) + vc->vc_intensity = 2; + vc->vc_par[i] -= 60; + } if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37) vc->vc_color = color_table[vc->vc_par[i] - 30] | (vc->vc_color & 0xf0); |