diff options
Diffstat (limited to 'drivers/tty/serial/8250')
-rw-r--r-- | drivers/tty/serial/8250/8250.c | 132 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250.h | 50 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_dma.c | 216 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 257 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_early.c | 2 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_pci.c | 342 | ||||
-rw-r--r-- | drivers/tty/serial/8250/Kconfig | 27 | ||||
-rw-r--r-- | drivers/tty/serial/8250/Makefile | 1 |
8 files changed, 896 insertions, 131 deletions
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index f9320437a64..0efc815a496 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -239,13 +239,6 @@ static const struct serial8250_config uart_config[] = { .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO | UART_CAP_UUE | UART_CAP_RTOIE, }, - [PORT_RM9000] = { - .name = "RM9000", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO, - }, [PORT_OCTEON] = { .name = "OCTEON", .fifo_size = 64, @@ -324,9 +317,9 @@ static void default_serial_dl_write(struct uart_8250_port *up, int value) serial_out(up, UART_DLM, value >> 8 & 0xff); } -#ifdef CONFIG_MIPS_ALCHEMY +#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) -/* Au1x00 UART hardware has a weird register layout */ +/* Au1x00/RT288x UART hardware has a weird register layout */ static const u8 au_io_in_map[] = { [UART_RX] = 0, [UART_IER] = 2, @@ -370,56 +363,6 @@ static void au_serial_dl_write(struct uart_8250_port *up, int value) #endif -#ifdef CONFIG_SERIAL_8250_RM9K - -static const u8 - regmap_in[8] = { - [UART_RX] = 0x00, - [UART_IER] = 0x0c, - [UART_IIR] = 0x14, - [UART_LCR] = 0x1c, - [UART_MCR] = 0x20, - [UART_LSR] = 0x24, - [UART_MSR] = 0x28, - [UART_SCR] = 0x2c - }, - regmap_out[8] = { - [UART_TX] = 0x04, - [UART_IER] = 0x0c, - [UART_FCR] = 0x18, - [UART_LCR] = 0x1c, - [UART_MCR] = 0x20, - [UART_LSR] = 0x24, - [UART_MSR] = 0x28, - [UART_SCR] = 0x2c - }; - -static unsigned int rm9k_serial_in(struct uart_port *p, int offset) -{ - offset = regmap_in[offset] << p->regshift; - return readl(p->membase + offset); -} - -static void rm9k_serial_out(struct uart_port *p, int offset, int value) -{ - offset = regmap_out[offset] << p->regshift; - writel(value, p->membase + offset); -} - -static int rm9k_serial_dl_read(struct uart_8250_port *up) -{ - return ((__raw_readl(up->port.membase + 0x10) << 8) | - (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff; -} - -static void rm9k_serial_dl_write(struct uart_8250_port *up, int value) -{ - __raw_writel(value, up->port.membase + 0x08); - __raw_writel(value >> 8, up->port.membase + 0x10); -} - -#endif - static unsigned int hub6_serial_in(struct uart_port *p, int offset) { offset = offset << p->regshift; @@ -497,16 +440,7 @@ static void set_io_from_upio(struct uart_port *p) p->serial_out = mem32_serial_out; break; -#ifdef CONFIG_SERIAL_8250_RM9K - case UPIO_RM9000: - p->serial_in = rm9k_serial_in; - p->serial_out = rm9k_serial_out; - up->dl_read = rm9k_serial_dl_read; - up->dl_write = rm9k_serial_dl_write; - break; -#endif - -#ifdef CONFIG_MIPS_ALCHEMY +#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) case UPIO_AU: p->serial_in = au_serial_in; p->serial_out = au_serial_out; @@ -1341,7 +1275,9 @@ static void serial8250_start_tx(struct uart_port *port) struct uart_8250_port *up = container_of(port, struct uart_8250_port, port); - if (!(up->ier & UART_IER_THRI)) { + if (up->dma && !serial8250_tx_dma(up)) { + return; + } else if (!(up->ier & UART_IER_THRI)) { up->ier |= UART_IER_THRI; serial_port_out(port, UART_IER, up->ier); @@ -1349,9 +1285,7 @@ static void serial8250_start_tx(struct uart_port *port) unsigned char lsr; lsr = serial_in(up, UART_LSR); up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - if ((port->type == PORT_RM9000) ? - (lsr & UART_LSR_THRE) : - (lsr & UART_LSR_TEMT)) + if (lsr & UART_LSR_TEMT) serial8250_tx_chars(up); } } @@ -1397,7 +1331,6 @@ unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) { struct uart_port *port = &up->port; - struct tty_struct *tty = port->state->port.tty; unsigned char ch; int max_count = 256; char flag; @@ -1462,7 +1395,7 @@ ignore_char: lsr = serial_in(up, UART_LSR); } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); spin_unlock(&port->lock); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(&port->state->port); spin_lock(&port->lock); return lsr; } @@ -1547,6 +1480,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) unsigned long flags; struct uart_8250_port *up = container_of(port, struct uart_8250_port, port); + int dma_err = 0; if (iir & UART_IIR_NO_INT) return 0; @@ -1557,8 +1491,13 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) DEBUG_INTR("status = %x...", status); - if (status & (UART_LSR_DR | UART_LSR_BI)) - status = serial8250_rx_chars(up, status); + if (status & (UART_LSR_DR | UART_LSR_BI)) { + if (up->dma) + dma_err = serial8250_rx_dma(up, iir); + + if (!up->dma || dma_err) + status = serial8250_rx_chars(up, status); + } serial8250_modem_status(up); if (status & UART_LSR_THRE) serial8250_tx_chars(up); @@ -1991,9 +1930,12 @@ static int serial8250_startup(struct uart_port *port) if (port->type == PORT_8250_CIR) return -ENODEV; - port->fifosize = uart_config[up->port.type].fifo_size; - up->tx_loadsz = uart_config[up->port.type].tx_loadsz; - up->capabilities = uart_config[up->port.type].flags; + if (!port->fifosize) + port->fifosize = uart_config[port->type].fifo_size; + if (!up->tx_loadsz) + up->tx_loadsz = uart_config[port->type].tx_loadsz; + if (!up->capabilities) + up->capabilities = uart_config[port->type].flags; up->mcr = 0; if (port->iotype != up->cur_iotype) @@ -2198,6 +2140,18 @@ dont_test_tx_en: up->msr_saved_flags = 0; /* + * Request DMA channels for both RX and TX. + */ + if (up->dma) { + retval = serial8250_request_dma(up); + if (retval) { + pr_warn_ratelimited("ttyS%d - failed to request DMA\n", + serial_index(port)); + up->dma = NULL; + } + } + + /* * Finally, enable interrupts. Note: Modem status interrupts * are set via set_termios(), which will be occurring imminently * anyway, so we don't enable them here. @@ -2230,6 +2184,9 @@ static void serial8250_shutdown(struct uart_port *port) up->ier = 0; serial_port_out(port, UART_IER, 0); + if (up->dma) + serial8250_release_dma(up); + spin_lock_irqsave(&port->lock, flags); if (port->flags & UPF_FOURPORT) { /* reset interrupts on the AST Fourport board */ @@ -2826,9 +2783,12 @@ static void serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type) { up->port.type = type; - up->port.fifosize = uart_config[type].fifo_size; - up->capabilities = uart_config[type].flags; - up->tx_loadsz = uart_config[type].tx_loadsz; + if (!up->port.fifosize) + up->port.fifosize = uart_config[type].fifo_size; + if (!up->tx_loadsz) + up->tx_loadsz = uart_config[type].tx_loadsz; + if (!up->capabilities) + up->capabilities = uart_config[type].flags; } static void __init @@ -3262,6 +3222,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->bugs = up->bugs; uart->port.mapbase = up->port.mapbase; uart->port.private_data = up->port.private_data; + uart->port.fifosize = up->port.fifosize; + uart->tx_loadsz = up->tx_loadsz; + uart->capabilities = up->capabilities; + if (up->port.dev) uart->port.dev = up->port.dev; @@ -3287,6 +3251,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->dl_read = up->dl_read; if (up->dl_write) uart->dl_write = up->dl_write; + if (up->dma) + uart->dma = up->dma; if (serial8250_isa_config != NULL) serial8250_isa_config(0, &uart->port, diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 12caa1292b7..34eb676916f 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -12,6 +12,35 @@ */ #include <linux/serial_8250.h> +#include <linux/dmaengine.h> + +struct uart_8250_dma { + dma_filter_fn fn; + void *rx_param; + void *tx_param; + + int rx_chan_id; + int tx_chan_id; + + struct dma_slave_config rxconf; + struct dma_slave_config txconf; + + struct dma_chan *rxchan; + struct dma_chan *txchan; + + dma_addr_t rx_addr; + dma_addr_t tx_addr; + + dma_cookie_t rx_cookie; + dma_cookie_t tx_cookie; + + void *rx_buf; + + size_t rx_size; + size_t tx_size; + + unsigned char tx_running:1; +}; struct old_serial_port { unsigned int uart; @@ -143,3 +172,24 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt) return 0; } #endif + +#ifdef CONFIG_SERIAL_8250_DMA +extern int serial8250_tx_dma(struct uart_8250_port *); +extern int serial8250_rx_dma(struct uart_8250_port *, unsigned int iir); +extern int serial8250_request_dma(struct uart_8250_port *); +extern void serial8250_release_dma(struct uart_8250_port *); +#else +static inline int serial8250_tx_dma(struct uart_8250_port *p) +{ + return -1; +} +static inline int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) +{ + return -1; +} +static inline int serial8250_request_dma(struct uart_8250_port *p) +{ + return -1; +} +static inline void serial8250_release_dma(struct uart_8250_port *p) { } +#endif diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c new file mode 100644 index 00000000000..b9f7fd28112 --- /dev/null +++ b/drivers/tty/serial/8250/8250_dma.c @@ -0,0 +1,216 @@ +/* + * 8250_dma.c - DMA Engine API support for 8250.c + * + * Copyright (C) 2013 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial_reg.h> +#include <linux/dma-mapping.h> + +#include "8250.h" + +static void __dma_tx_complete(void *param) +{ + struct uart_8250_port *p = param; + struct uart_8250_dma *dma = p->dma; + struct circ_buf *xmit = &p->port.state->xmit; + + dma->tx_running = 0; + + dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr, + UART_XMIT_SIZE, DMA_TO_DEVICE); + + xmit->tail += dma->tx_size; + xmit->tail &= UART_XMIT_SIZE - 1; + p->port.icount.tx += dma->tx_size; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&p->port); + + if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) { + serial8250_tx_dma(p); + uart_write_wakeup(&p->port); + } +} + +static void __dma_rx_complete(void *param) +{ + struct uart_8250_port *p = param; + struct uart_8250_dma *dma = p->dma; + struct tty_port *tty_port = &p->port.state->port; + struct dma_tx_state state; + int count; + + dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); + + dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); + dmaengine_terminate_all(dma->rxchan); + + count = dma->rx_size - state.residue; + + tty_insert_flip_string(tty_port, dma->rx_buf, count); + p->port.icount.rx += count; + + tty_flip_buffer_push(tty_port); +} + +int serial8250_tx_dma(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + struct circ_buf *xmit = &p->port.state->xmit; + struct dma_async_tx_descriptor *desc; + + if (dma->tx_running) + return -EBUSY; + + dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + if (!dma->tx_size) + return -EINVAL; + + desc = dmaengine_prep_slave_single(dma->txchan, + dma->tx_addr + xmit->tail, + dma->tx_size, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + return -EBUSY; + + dma->tx_running = 1; + + desc->callback = __dma_tx_complete; + desc->callback_param = p; + + dma->tx_cookie = dmaengine_submit(desc); + + dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr, + UART_XMIT_SIZE, DMA_TO_DEVICE); + + dma_async_issue_pending(dma->txchan); + + return 0; +} +EXPORT_SYMBOL_GPL(serial8250_tx_dma); + +int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) +{ + struct uart_8250_dma *dma = p->dma; + struct dma_async_tx_descriptor *desc; + struct dma_tx_state state; + int dma_status; + + /* + * If RCVR FIFO trigger level was not reached, complete the transfer and + * let 8250.c copy the remaining data. + */ + if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) { + dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, + &state); + if (dma_status == DMA_IN_PROGRESS) { + dmaengine_pause(dma->rxchan); + __dma_rx_complete(p); + } + return -ETIMEDOUT; + } + + desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, + dma->rx_size, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + return -EBUSY; + + desc->callback = __dma_rx_complete; + desc->callback_param = p; + + dma->rx_cookie = dmaengine_submit(desc); + + dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); + + dma_async_issue_pending(dma->rxchan); + + return 0; +} +EXPORT_SYMBOL_GPL(serial8250_rx_dma); + +int serial8250_request_dma(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + dma_cap_mask_t mask; + + dma->rxconf.src_addr = p->port.mapbase + UART_RX; + dma->txconf.dst_addr = p->port.mapbase + UART_TX; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + /* Get a channel for RX */ + dma->rxchan = dma_request_channel(mask, dma->fn, dma->rx_param); + if (!dma->rxchan) + return -ENODEV; + + dmaengine_slave_config(dma->rxchan, &dma->rxconf); + + /* Get a channel for TX */ + dma->txchan = dma_request_channel(mask, dma->fn, dma->tx_param); + if (!dma->txchan) { + dma_release_channel(dma->rxchan); + return -ENODEV; + } + + dmaengine_slave_config(dma->txchan, &dma->txconf); + + /* RX buffer */ + if (!dma->rx_size) + dma->rx_size = PAGE_SIZE; + + dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size, + &dma->rx_addr, GFP_KERNEL); + if (!dma->rx_buf) { + dma_release_channel(dma->rxchan); + dma_release_channel(dma->txchan); + return -ENOMEM; + } + + /* TX buffer */ + dma->tx_addr = dma_map_single(dma->txchan->device->dev, + p->port.state->xmit.buf, + UART_XMIT_SIZE, + DMA_TO_DEVICE); + + dev_dbg_ratelimited(p->port.dev, "got both dma channels\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(serial8250_request_dma); + +void serial8250_release_dma(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + + if (!dma) + return; + + /* Release RX resources */ + dmaengine_terminate_all(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); + dma_unmap_single(dma->txchan->device->dev, dma->tx_addr, + UART_XMIT_SIZE, DMA_TO_DEVICE); + dma_release_channel(dma->txchan); + dma->txchan = NULL; + dma->tx_running = 0; + + dev_dbg_ratelimited(p->port.dev, "dma channels released\n"); +} +EXPORT_SYMBOL_GPL(serial8250_release_dma); diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 096d2ef48b3..db0e66f6dd0 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -2,6 +2,7 @@ * Synopsys DesignWare 8250 driver. * * Copyright 2011 Picochip, Jamie Iles. + * Copyright 2013 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +25,34 @@ #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/acpi.h> + +#include "8250.h" + +/* Offsets for the DesignWare specific registers */ +#define DW_UART_USR 0x1f /* UART Status Register */ +#define DW_UART_CPR 0xf4 /* Component Parameter Register */ +#define DW_UART_UCV 0xf8 /* UART Component Version */ + +/* Intel Low Power Subsystem specific */ +#define LPSS_PRV_CLOCK_PARAMS 0x800 + +/* Component Parameter Register bits */ +#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) +#define DW_UART_CPR_AFCE_MODE (1 << 4) +#define DW_UART_CPR_THRE_MODE (1 << 5) +#define DW_UART_CPR_SIR_MODE (1 << 6) +#define DW_UART_CPR_SIR_LP_MODE (1 << 7) +#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8) +#define DW_UART_CPR_FIFO_ACCESS (1 << 9) +#define DW_UART_CPR_FIFO_STAT (1 << 10) +#define DW_UART_CPR_SHADOW (1 << 11) +#define DW_UART_CPR_ENCODED_PARMS (1 << 12) +#define DW_UART_CPR_DMA_EXTRA (1 << 13) +#define DW_UART_CPR_FIFO_MODE (0xff << 16) +/* Helper for fifo size calculation */ +#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16) + struct dw8250_data { int last_lcr; @@ -66,9 +95,6 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) return readl(p->membase + offset); } -/* Offset for the DesignWare's UART Status Register. */ -#define UART_USR 0x1f - static int dw8250_handle_irq(struct uart_port *p) { struct dw8250_data *d = p->private_data; @@ -78,7 +104,7 @@ static int dw8250_handle_irq(struct uart_port *p) return 1; } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { /* Clear the USR and write the LCR again. */ - (void)p->serial_in(p, UART_USR); + (void)p->serial_in(p, DW_UART_USR); p->serial_out(p, UART_LCR, d->last_lcr); return 1; @@ -87,61 +113,210 @@ static int dw8250_handle_irq(struct uart_port *p) return 0; } +static int dw8250_probe_of(struct uart_port *p) +{ + struct device_node *np = p->dev->of_node; + u32 val; + + if (!of_property_read_u32(np, "reg-io-width", &val)) { + switch (val) { + case 1: + break; + case 4: + p->iotype = UPIO_MEM32; + p->serial_in = dw8250_serial_in32; + p->serial_out = dw8250_serial_out32; + break; + default: + dev_err(p->dev, "unsupported reg-io-width (%u)\n", val); + return -EINVAL; + } + } + + if (!of_property_read_u32(np, "reg-shift", &val)) + p->regshift = val; + + if (of_property_read_u32(np, "clock-frequency", &val)) { + dev_err(p->dev, "no clock-frequency property set\n"); + return -EINVAL; + } + p->uartclk = val; + + return 0; +} + +#ifdef CONFIG_ACPI +static bool dw8250_acpi_dma_filter(struct dma_chan *chan, void *parm) +{ + return chan->chan_id == *(int *)parm; +} + +static acpi_status +dw8250_acpi_walk_resource(struct acpi_resource *res, void *data) +{ + struct uart_port *p = data; + struct uart_8250_port *port; + struct uart_8250_dma *dma; + struct acpi_resource_fixed_dma *fixed_dma; + struct dma_slave_config *slave; + + port = container_of(p, struct uart_8250_port, port); + + switch (res->type) { + case ACPI_RESOURCE_TYPE_FIXED_DMA: + fixed_dma = &res->data.fixed_dma; + + /* TX comes first */ + if (!port->dma) { + dma = devm_kzalloc(p->dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return AE_NO_MEMORY; + + port->dma = dma; + slave = &dma->txconf; + + slave->direction = DMA_MEM_TO_DEV; + slave->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave->slave_id = fixed_dma->request_lines; + slave->dst_maxburst = port->tx_loadsz / 4; + + dma->tx_chan_id = fixed_dma->channels; + dma->tx_param = &dma->tx_chan_id; + dma->fn = dw8250_acpi_dma_filter; + } else { + dma = port->dma; + slave = &dma->rxconf; + + slave->direction = DMA_DEV_TO_MEM; + slave->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave->slave_id = fixed_dma->request_lines; + slave->src_maxburst = p->fifosize / 4; + + dma->rx_chan_id = fixed_dma->channels; + dma->rx_param = &dma->rx_chan_id; + } + + break; + } + + return AE_OK; +} + +static int dw8250_probe_acpi(struct uart_port *p) +{ + const struct acpi_device_id *id; + acpi_status status; + u32 reg; + + id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev); + if (!id) + return -ENODEV; + + p->iotype = UPIO_MEM32; + p->serial_in = dw8250_serial_in32; + p->serial_out = dw8250_serial_out32; + p->regshift = 2; + p->uartclk = (unsigned int)id->driver_data; + + status = acpi_walk_resources(ACPI_HANDLE(p->dev), METHOD_NAME__CRS, + dw8250_acpi_walk_resource, p); + if (ACPI_FAILURE(status)) { + dev_err_ratelimited(p->dev, "%s failed \"%s\"\n", __func__, + acpi_format_exception(status)); + return -ENODEV; + } + + /* Fix Haswell issue where the clocks do not get enabled */ + if (!strcmp(id->id, "INT33C4") || !strcmp(id->id, "INT33C5")) { + reg = readl(p->membase + LPSS_PRV_CLOCK_PARAMS); + writel(reg | 1, p->membase + LPSS_PRV_CLOCK_PARAMS); + } + + return 0; +} +#else +static inline int dw8250_probe_acpi(struct uart_port *p) +{ + return -ENODEV; +} +#endif /* CONFIG_ACPI */ + +static void dw8250_setup_port(struct uart_8250_port *up) +{ + struct uart_port *p = &up->port; + u32 reg = readl(p->membase + DW_UART_UCV); + + /* + * If the Component Version Register returns zero, we know that + * ADDITIONAL_FEATURES are not enabled. No need to go any further. + */ + if (!reg) + return; + + dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n", + (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); + + reg = readl(p->membase + DW_UART_CPR); + if (!reg) + return; + + /* Select the type based on fifo */ + if (reg & DW_UART_CPR_FIFO_MODE) { + p->type = PORT_16550A; + p->flags |= UPF_FIXED_TYPE; + p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); + up->tx_loadsz = p->fifosize; + } +} + static int dw8250_probe(struct platform_device *pdev) { struct uart_8250_port uart = {}; struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - struct device_node *np = pdev->dev.of_node; - u32 val; struct dw8250_data *data; + int err; if (!regs || !irq) { dev_err(&pdev->dev, "no registers/irq defined\n"); return -EINVAL; } - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - uart.port.private_data = data; - spin_lock_init(&uart.port.lock); uart.port.mapbase = regs->start; uart.port.irq = irq->start; uart.port.handle_irq = dw8250_handle_irq; uart.port.type = PORT_8250; - uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | - UPF_FIXED_PORT | UPF_FIXED_TYPE; + uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; uart.port.dev = &pdev->dev; + uart.port.membase = ioremap(regs->start, resource_size(regs)); + if (!uart.port.membase) + return -ENOMEM; + uart.port.iotype = UPIO_MEM; uart.port.serial_in = dw8250_serial_in; uart.port.serial_out = dw8250_serial_out; - if (!of_property_read_u32(np, "reg-io-width", &val)) { - switch (val) { - case 1: - break; - case 4: - uart.port.iotype = UPIO_MEM32; - uart.port.serial_in = dw8250_serial_in32; - uart.port.serial_out = dw8250_serial_out32; - break; - default: - dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n", - val); - return -EINVAL; - } + + dw8250_setup_port(&uart); + + if (pdev->dev.of_node) { + err = dw8250_probe_of(&uart.port); + if (err) + return err; + } else if (ACPI_HANDLE(&pdev->dev)) { + err = dw8250_probe_acpi(&uart.port); + if (err) + return err; + } else { + return -ENODEV; } - if (!of_property_read_u32(np, "reg-shift", &val)) - uart.port.regshift = val; + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; - if (of_property_read_u32(np, "clock-frequency", &val)) { - dev_err(&pdev->dev, "no clock-frequency property set\n"); - return -EINVAL; - } - uart.port.uartclk = val; + uart.port.private_data = data; data->line = serial8250_register_8250_port(&uart); if (data->line < 0) @@ -184,17 +359,25 @@ static int dw8250_resume(struct platform_device *pdev) #define dw8250_resume NULL #endif /* CONFIG_PM */ -static const struct of_device_id dw8250_match[] = { +static const struct of_device_id dw8250_of_match[] = { { .compatible = "snps,dw-apb-uart" }, { /* Sentinel */ } }; -MODULE_DEVICE_TABLE(of, dw8250_match); +MODULE_DEVICE_TABLE(of, dw8250_of_match); + +static const struct acpi_device_id dw8250_acpi_match[] = { + { "INT33C4", 100000000 }, + { "INT33C5", 100000000 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); static struct platform_driver dw8250_platform_driver = { .driver = { .name = "dw-apb-uart", .owner = THIS_MODULE, - .of_match_table = dw8250_match, + .of_match_table = dw8250_of_match, + .acpi_match_table = ACPI_PTR(dw8250_acpi_match), }, .probe = dw8250_probe, .remove = dw8250_remove, diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index f53a7db4350..721904f8efa 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -194,7 +194,7 @@ static int __init parse_options(struct early_serial8250_device *device, options++; device->baud = simple_strtoul(options, NULL, 0); length = min(strcspn(options, " "), sizeof(device->options)); - strncpy(device->options, options, length); + strlcpy(device->options, options, length); } else { device->baud = probe_baud(port); snprintf(device->options, sizeof(device->options), "%u", diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index a27a98e1b06..791c5a77ec6 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1040,6 +1040,253 @@ static int pci_asix_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +/* Quatech devices have their own extra interface features */ + +struct quatech_feature { + u16 devid; + bool amcc; +}; + +#define QPCR_TEST_FOR1 0x3F +#define QPCR_TEST_GET1 0x00 +#define QPCR_TEST_FOR2 0x40 +#define QPCR_TEST_GET2 0x40 +#define QPCR_TEST_FOR3 0x80 +#define QPCR_TEST_GET3 0x40 +#define QPCR_TEST_FOR4 0xC0 +#define QPCR_TEST_GET4 0x80 + +#define QOPR_CLOCK_X1 0x0000 +#define QOPR_CLOCK_X2 0x0001 +#define QOPR_CLOCK_X4 0x0002 +#define QOPR_CLOCK_X8 0x0003 +#define QOPR_CLOCK_RATE_MASK 0x0003 + + +static struct quatech_feature quatech_cards[] = { + { PCI_DEVICE_ID_QUATECH_QSC100, 1 }, + { PCI_DEVICE_ID_QUATECH_DSC100, 1 }, + { PCI_DEVICE_ID_QUATECH_DSC100E, 0 }, + { PCI_DEVICE_ID_QUATECH_DSC200, 1 }, + { PCI_DEVICE_ID_QUATECH_DSC200E, 0 }, + { PCI_DEVICE_ID_QUATECH_ESC100D, 1 }, + { PCI_DEVICE_ID_QUATECH_ESC100M, 1 }, + { PCI_DEVICE_ID_QUATECH_QSCP100, 1 }, + { PCI_DEVICE_ID_QUATECH_DSCP100, 1 }, + { PCI_DEVICE_ID_QUATECH_QSCP200, 1 }, + { PCI_DEVICE_ID_QUATECH_DSCP200, 1 }, + { PCI_DEVICE_ID_QUATECH_ESCLP100, 0 }, + { PCI_DEVICE_ID_QUATECH_QSCLP100, 0 }, + { PCI_DEVICE_ID_QUATECH_DSCLP100, 0 }, + { PCI_DEVICE_ID_QUATECH_SSCLP100, 0 }, + { PCI_DEVICE_ID_QUATECH_QSCLP200, 0 }, + { PCI_DEVICE_ID_QUATECH_DSCLP200, 0 }, + { PCI_DEVICE_ID_QUATECH_SSCLP200, 0 }, + { PCI_DEVICE_ID_QUATECH_SPPXP_100, 0 }, + { 0, } +}; + +static int pci_quatech_amcc(u16 devid) +{ + struct quatech_feature *qf = &quatech_cards[0]; + while (qf->devid) { + if (qf->devid == devid) + return qf->amcc; + qf++; + } + pr_err("quatech: unknown port type '0x%04X'.\n", devid); + return 0; +}; + +static int pci_quatech_rqopr(struct uart_8250_port *port) +{ + unsigned long base = port->port.iobase; + u8 LCR, val; + + LCR = inb(base + UART_LCR); + outb(0xBF, base + UART_LCR); + val = inb(base + UART_SCR); + outb(LCR, base + UART_LCR); + return val; +} + +static void pci_quatech_wqopr(struct uart_8250_port *port, u8 qopr) +{ + unsigned long base = port->port.iobase; + u8 LCR, val; + + LCR = inb(base + UART_LCR); + outb(0xBF, base + UART_LCR); + val = inb(base + UART_SCR); + outb(qopr, base + UART_SCR); + outb(LCR, base + UART_LCR); +} + +static int pci_quatech_rqmcr(struct uart_8250_port *port) +{ + unsigned long base = port->port.iobase; + u8 LCR, val, qmcr; + + LCR = inb(base + UART_LCR); + outb(0xBF, base + UART_LCR); + val = inb(base + UART_SCR); + outb(val | 0x10, base + UART_SCR); + qmcr = inb(base + UART_MCR); + outb(val, base + UART_SCR); + outb(LCR, base + UART_LCR); + + return qmcr; +} + +static void pci_quatech_wqmcr(struct uart_8250_port *port, u8 qmcr) +{ + unsigned long base = port->port.iobase; + u8 LCR, val; + + LCR = inb(base + UART_LCR); + outb(0xBF, base + UART_LCR); + val = inb(base + UART_SCR); + outb(val | 0x10, base + UART_SCR); + outb(qmcr, base + UART_MCR); + outb(val, base + UART_SCR); + outb(LCR, base + UART_LCR); +} + +static int pci_quatech_has_qmcr(struct uart_8250_port *port) +{ + unsigned long base = port->port.iobase; + u8 LCR, val; + + LCR = inb(base + UART_LCR); + outb(0xBF, base + UART_LCR); + val = inb(base + UART_SCR); + if (val & 0x20) { + outb(0x80, UART_LCR); + if (!(inb(UART_SCR) & 0x20)) { + outb(LCR, base + UART_LCR); + return 1; + } + } + return 0; +} + +static int pci_quatech_test(struct uart_8250_port *port) +{ + u8 reg; + u8 qopr = pci_quatech_rqopr(port); + pci_quatech_wqopr(port, qopr & QPCR_TEST_FOR1); + reg = pci_quatech_rqopr(port) & 0xC0; + if (reg != QPCR_TEST_GET1) + return -EINVAL; + pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR2); + reg = pci_quatech_rqopr(port) & 0xC0; + if (reg != QPCR_TEST_GET2) + return -EINVAL; + pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR3); + reg = pci_quatech_rqopr(port) & 0xC0; + if (reg != QPCR_TEST_GET3) + return -EINVAL; + pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR4); + reg = pci_quatech_rqopr(port) & 0xC0; + if (reg != QPCR_TEST_GET4) + return -EINVAL; + + pci_quatech_wqopr(port, qopr); + return 0; +} + +static int pci_quatech_clock(struct uart_8250_port *port) +{ + u8 qopr, reg, set; + unsigned long clock; + + if (pci_quatech_test(port) < 0) + return 1843200; + + qopr = pci_quatech_rqopr(port); + + pci_quatech_wqopr(port, qopr & ~QOPR_CLOCK_X8); + reg = pci_quatech_rqopr(port); + if (reg & QOPR_CLOCK_X8) { + clock = 1843200; + goto out; + } + pci_quatech_wqopr(port, qopr | QOPR_CLOCK_X8); + reg = pci_quatech_rqopr(port); + if (!(reg & QOPR_CLOCK_X8)) { + clock = 1843200; + goto out; + } + reg &= QOPR_CLOCK_X8; + if (reg == QOPR_CLOCK_X2) { + clock = 3685400; + set = QOPR_CLOCK_X2; + } else if (reg == QOPR_CLOCK_X4) { + clock = 7372800; + set = QOPR_CLOCK_X4; + } else if (reg == QOPR_CLOCK_X8) { + clock = 14745600; + set = QOPR_CLOCK_X8; + } else { + clock = 1843200; + set = QOPR_CLOCK_X1; + } + qopr &= ~QOPR_CLOCK_RATE_MASK; + qopr |= set; + +out: + pci_quatech_wqopr(port, qopr); + return clock; +} + +static int pci_quatech_rs422(struct uart_8250_port *port) +{ + u8 qmcr; + int rs422 = 0; + + if (!pci_quatech_has_qmcr(port)) + return 0; + qmcr = pci_quatech_rqmcr(port); + pci_quatech_wqmcr(port, 0xFF); + if (pci_quatech_rqmcr(port)) + rs422 = 1; + pci_quatech_wqmcr(port, qmcr); + return rs422; +} + +static int pci_quatech_init(struct pci_dev *dev) +{ + if (pci_quatech_amcc(dev->device)) { + unsigned long base = pci_resource_start(dev, 0); + if (base) { + u32 tmp; + outl(inl(base + 0x38), base + 0x38); + tmp = inl(base + 0x3c); + outl(tmp | 0x01000000, base + 0x3c); + outl(tmp, base + 0x3c); + } + } + return 0; +} + +static int pci_quatech_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + /* Needed by pci_quatech calls below */ + port->port.iobase = pci_resource_start(priv->dev, FL_GET_BASE(board->flags)); + /* Set up the clocking */ + port->port.uartclk = pci_quatech_clock(port); + /* For now just warn about RS422 */ + if (pci_quatech_rs422(port)) + pr_warn("quatech: software control of RS422 features not currently supported.\n"); + return pci_default_setup(priv, board, port, idx); +} + +static void pci_quatech_exit(struct pci_dev *dev) +{ +} + static int pci_default_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -1318,6 +1565,9 @@ pci_wch_ch353_setup(struct serial_private *priv, #define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022 #define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a +#define PCI_VENDOR_ID_SUNIX 0x1fd4 +#define PCI_DEVICE_ID_SUNIX_1999 0x1999 + /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 @@ -1541,6 +1791,16 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_ni8430_setup, .exit = pci_ni8430_exit, }, + /* Quatech */ + { + .vendor = PCI_VENDOR_ID_QUATECH, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .init = pci_quatech_init, + .setup = pci_quatech_setup, + .exit = pci_quatech_exit, + }, /* * Panacom */ @@ -1704,6 +1964,23 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_timedia_setup, }, /* + * SUNIX (Timedia) cards + * Do not "probe" for these cards as there is at least one combination + * card that should be handled by parport_pc that doesn't match the + * rule in pci_timedia_probe. + * It is part number is MIO5079A but its subdevice ID is 0x0102. + * There are some boards with part number SER5037AL that report + * subdevice ID 0x0002. + */ + { + .vendor = PCI_VENDOR_ID_SUNIX, + .device = PCI_DEVICE_ID_SUNIX_1999, + .subvendor = PCI_VENDOR_ID_SUNIX, + .subdevice = PCI_ANY_ID, + .init = pci_timedia_init, + .setup = pci_timedia_setup, + }, + /* * Exar cards */ { @@ -3506,18 +3783,70 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS, 0x10b5, 0x106a, 0, 0, pbn_plx_romulus }, + /* + * Quatech cards. These actually have configurable clocks but for + * now we just use the default. + * + * 100 series are RS232, 200 series RS422, + */ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b1_4_115200 }, { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b1_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_4_115200 }, { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b1_8_115200 }, { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b1_8_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_4_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_4_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_4_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_1_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_4_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_1_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESCLP100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_8_115200 }, + { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0, @@ -3902,6 +4231,19 @@ static struct pci_device_id serial_pci_tbl[] = { pbn_b0_bt_1_921600 }, /* + * SUNIX (TIMEDIA) + */ + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, + pbn_b0_bt_1_921600 }, + + { PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, + PCI_VENDOR_ID_SUNIX, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, + pbn_b0_bt_1_921600 }, + + /* * AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org> */ { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028, diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index c31133a6ea8..2ef9537bcb2 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -84,6 +84,14 @@ config SERIAL_8250_GSC depends on SERIAL_8250 && GSC default SERIAL_8250 +config SERIAL_8250_DMA + bool "DMA support for 16550 compatible UART controllers" if EXPERT + depends on SERIAL_8250 && DMADEVICES=y + default SERIAL_8250 + help + This builds DMA support that can be used with 8250/16650 + compatible UART controllers that support DMA signaling. + config SERIAL_8250_PCI tristate "8250/16550 PCI device support" if EXPERT depends on SERIAL_8250 && PCI @@ -249,15 +257,6 @@ config SERIAL_8250_ACORN system, say Y to this option. The driver can handle 1, 2, or 3 port cards. If unsure, say N. -config SERIAL_8250_RM9K - bool "Support for MIPS RM9xxx integrated serial port" - depends on SERIAL_8250 != n && SERIAL_RM9000 - select SERIAL_8250_SHARE_IRQ - help - Selecting this option will add support for the integrated serial - port hardware found on MIPS RM9122 and similar processors. - If unsure, say N. - config SERIAL_8250_FSL bool depends on SERIAL_8250_CONSOLE && PPC_UDBG_16550 @@ -265,7 +264,7 @@ config SERIAL_8250_FSL config SERIAL_8250_DW tristate "Support for Synopsys DesignWare 8250 quirks" - depends on SERIAL_8250 && OF + depends on SERIAL_8250 help Selecting this option will enable handling of the extra features present in the Synopsys DesignWare APB UART. @@ -277,3 +276,11 @@ config SERIAL_8250_EM Selecting this option will add support for the integrated serial port hardware found on the Emma Mobile line of processors. If unsure, say N. + +config SERIAL_8250_RT288X + bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support" + depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883) + help + If you have a Ralink RT288x/RT305x SoC based board and want to use the + serial port, say Y to this option. The driver can handle up to 2 serial + ports. If unsure, say N. diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index 108fe7fe13e..a23838a4d53 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250_core.o 8250_core-y := 8250.o 8250_core-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o +8250_core-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o |