summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
authorJohn Stultz <john.stultz@linaro.org>2011-04-05 12:21:10 -0700
committerJohn Stultz <john.stultz@linaro.org>2011-04-05 12:21:10 -0700
commit4ce7ea0bfbb301ffb79154b6cecd2ef030db4cdf (patch)
treea7ad87580793912a9da208e7a9ea21d6c7768f08 /drivers/tty
parent4450182f400f1a5f50b1680faec25af2315c2849 (diff)
parent7c4bc9c2662c6d9840afed0e29eb01314af9bb78 (diff)
Merge branch 'upstream/linaro.38' into linaro-android.38
Conflicts: arch/arm/kernel/signal.c drivers/mmc/card/block.c drivers/mtd/nand/Kconfig include/linux/amba/mmci.h kernel/printk.c mm/shmem.c net/socket.c
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/8250.c33
-rw-r--r--drivers/tty/serial/amba-pl011.c511
-rw-r--r--drivers/tty/serial/mrst_max3110.c2
-rw-r--r--drivers/tty/serial/msm_serial.c286
-rw-r--r--drivers/tty/serial/msm_serial.h28
-rw-r--r--drivers/tty/serial/of_serial.c18
-rw-r--r--drivers/tty/serial/omap-serial.c5
7 files changed, 754 insertions, 129 deletions
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index 3975df6f7fd..b3b881bc471 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -954,6 +954,23 @@ static int broken_efr(struct uart_8250_port *up)
return 0;
}
+static inline int ns16550a_goto_highspeed(struct uart_8250_port *up)
+{
+ unsigned char status;
+
+ status = serial_in(up, 0x04); /* EXCR2 */
+#define PRESL(x) ((x) & 0x30)
+ if (PRESL(status) == 0x10) {
+ /* already in high speed mode */
+ return 0;
+ } else {
+ status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
+ status |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
+ serial_outp(up, 0x04, status);
+ }
+ return 1;
+}
+
/*
* We know that the chip has FIFOs. Does it have an EFR? The
* EFR is located in the same register position as the IIR and
@@ -1025,12 +1042,8 @@ static void autoconfig_16550a(struct uart_8250_port *up)
quot = serial_dl_read(up);
quot <<= 3;
- status1 = serial_in(up, 0x04); /* EXCR2 */
- status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
- status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
- serial_outp(up, 0x04, status1);
-
- serial_dl_write(up, quot);
+ if (ns16550a_goto_highspeed(up))
+ serial_dl_write(up, quot);
serial_outp(up, UART_LCR, 0);
@@ -3025,17 +3038,13 @@ void serial8250_resume_port(int line)
struct uart_8250_port *up = &serial8250_ports[line];
if (up->capabilities & UART_NATSEMI) {
- unsigned char tmp;
-
/* Ensure it's still in high speed mode */
serial_outp(up, UART_LCR, 0xE0);
- tmp = serial_in(up, 0x04); /* EXCR2 */
- tmp &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
- tmp |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
- serial_outp(up, 0x04, tmp);
+ ns16550a_goto_highspeed(up);
serial_outp(up, UART_LCR, 0);
+ up->port.uartclk = 921600*16;
}
uart_resume_port(&serial8250_reg, &up->port);
}
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 0dae46f9102..57731e87008 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -96,6 +96,22 @@ static struct vendor_data vendor_st = {
};
/* Deals with DMA transactions */
+
+struct pl011_sgbuf {
+ struct scatterlist sg;
+ char *buf;
+};
+
+struct pl011_dmarx_data {
+ struct dma_chan *chan;
+ struct completion complete;
+ bool use_buf_b;
+ struct pl011_sgbuf sgbuf_a;
+ struct pl011_sgbuf sgbuf_b;
+ dma_cookie_t cookie;
+ bool running;
+};
+
struct pl011_dmatx_data {
struct dma_chan *chan;
struct scatterlist sg;
@@ -120,12 +136,70 @@ struct uart_amba_port {
char type[12];
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
- bool using_dma;
+ bool using_tx_dma;
+ bool using_rx_dma;
+ struct pl011_dmarx_data dmarx;
struct pl011_dmatx_data dmatx;
#endif
};
/*
+ * Reads up to 256 characters from the FIFO or until it's empty and
+ * inserts them into the TTY layer. Returns the number of characters
+ * read from the FIFO.
+ */
+static int pl011_fifo_to_tty(struct uart_amba_port *uap)
+{
+ u16 status, ch;
+ unsigned int flag, max_count = 256;
+ int fifotaken = 0;
+
+ while (max_count--) {
+ status = readw(uap->port.membase + UART01x_FR);
+ if (status & UART01x_FR_RXFE)
+ break;
+
+ /* Take chars from the FIFO and update status */
+ ch = readw(uap->port.membase + UART01x_DR) |
+ UART_DUMMY_DR_RX;
+ flag = TTY_NORMAL;
+ uap->port.icount.rx++;
+ fifotaken++;
+
+ if (unlikely(ch & UART_DR_ERROR)) {
+ if (ch & UART011_DR_BE) {
+ ch &= ~(UART011_DR_FE | UART011_DR_PE);
+ uap->port.icount.brk++;
+ if (uart_handle_break(&uap->port))
+ continue;
+ } else if (ch & UART011_DR_PE)
+ uap->port.icount.parity++;
+ else if (ch & UART011_DR_FE)
+ uap->port.icount.frame++;
+ if (ch & UART011_DR_OE)
+ uap->port.icount.overrun++;
+
+ ch &= uap->port.read_status_mask;
+
+ if (ch & UART011_DR_BE)
+ flag = TTY_BREAK;
+ else if (ch & UART011_DR_PE)
+ flag = TTY_PARITY;
+ else if (ch & UART011_DR_FE)
+ flag = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(&uap->port, ch & 255))
+ continue;
+
+ uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
+ }
+
+ return fifotaken;
+}
+
+
+/*
* All the DMA operation mode stuff goes inside this ifdef.
* This assumes that you have a generic DMA device interface,
* no custom DMA interfaces are supported.
@@ -134,6 +208,31 @@ struct uart_amba_port {
#define PL011_DMA_BUFFER_SIZE PAGE_SIZE
+static int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg,
+ enum dma_data_direction dir)
+{
+ sg->buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL);
+ if (!sg->buf)
+ return -ENOMEM;
+
+ sg_init_one(&sg->sg, sg->buf, PL011_DMA_BUFFER_SIZE);
+
+ if (dma_map_sg(chan->device->dev, &sg->sg, 1, dir) != 1) {
+ kfree(sg->buf);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg,
+ enum dma_data_direction dir)
+{
+ if (sg->buf) {
+ dma_unmap_sg(chan->device->dev, &sg->sg, 1, dir);
+ kfree(sg->buf);
+ }
+}
+
static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
{
/* DMA is the sole user of the platform data right now */
@@ -153,7 +252,7 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
return;
}
- /* Try to acquire a generic DMA engine slave channel */
+ /* Try to acquire a generic DMA engine slave TX channel */
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
@@ -168,6 +267,28 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
dev_info(uap->port.dev, "DMA channel TX %s\n",
dma_chan_name(uap->dmatx.chan));
+
+ /* Optionally make use of an RX channel as well */
+ if (plat->dma_rx_param) {
+ struct dma_slave_config rx_conf = {
+ .src_addr = uap->port.mapbase + UART01x_DR,
+ .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
+ .direction = DMA_FROM_DEVICE,
+ .src_maxburst = uap->fifosize >> 1,
+ };
+
+ chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
+ if (!chan) {
+ dev_err(uap->port.dev, "no RX DMA channel!\n");
+ return;
+ }
+
+ dmaengine_slave_config(chan, &rx_conf);
+ uap->dmarx.chan = chan;
+
+ dev_info(uap->port.dev, "DMA channel RX %s\n",
+ dma_chan_name(uap->dmarx.chan));
+ }
}
#ifndef MODULE
@@ -219,9 +340,10 @@ static void pl011_dma_remove(struct uart_amba_port *uap)
/* TODO: remove the initcall if it has not yet executed */
if (uap->dmatx.chan)
dma_release_channel(uap->dmatx.chan);
+ if (uap->dmarx.chan)
+ dma_release_channel(uap->dmarx.chan);
}
-
/* Forward declare this for the refill routine */
static int pl011_dma_tx_refill(struct uart_amba_port *uap);
@@ -380,7 +502,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
*/
static bool pl011_dma_tx_irq(struct uart_amba_port *uap)
{
- if (!uap->using_dma)
+ if (!uap->using_tx_dma)
return false;
/*
@@ -432,7 +554,7 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
{
u16 dmacr;
- if (!uap->using_dma)
+ if (!uap->using_tx_dma)
return false;
if (!uap->port.x_char) {
@@ -492,7 +614,7 @@ static void pl011_dma_flush_buffer(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
- if (!uap->using_dma)
+ if (!uap->using_tx_dma)
return;
/* Avoid deadlock with the DMA engine callback */
@@ -508,9 +630,219 @@ static void pl011_dma_flush_buffer(struct uart_port *port)
}
}
+static void pl011_dma_rx_callback(void *data);
+
+static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
+{
+ struct dma_chan *rxchan = uap->dmarx.chan;
+ struct dma_device *dma_dev;
+ struct pl011_dmarx_data *dmarx = &uap->dmarx;
+ struct dma_async_tx_descriptor *desc;
+ struct pl011_sgbuf *sgbuf;
+
+ if (!rxchan)
+ return -EIO;
+
+ /* Start the RX DMA job */
+ sgbuf = uap->dmarx.use_buf_b ?
+ &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
+ dma_dev = rxchan->device;
+ desc = rxchan->device->device_prep_slave_sg(rxchan, &sgbuf->sg, 1,
+ DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ /*
+ * If the DMA engine is busy and cannot prepare a
+ * channel, no big deal, the driver will fall back
+ * to interrupt mode as a result of this error code.
+ */
+ if (!desc) {
+ uap->dmarx.running = false;
+ dmaengine_terminate_all(rxchan);
+ return -EBUSY;
+ }
+
+ /* Some data to go along to the callback */
+ desc->callback = pl011_dma_rx_callback;
+ desc->callback_param = uap;
+ dmarx->cookie = dmaengine_submit(desc);
+ dma_async_issue_pending(rxchan);
+
+ uap->dmacr |= UART011_RXDMAE;
+ writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ uap->dmarx.running = true;
+
+ uap->im &= ~UART011_RXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+
+ return 0;
+}
+
+/*
+ * This is called when either the DMA job is complete, or
+ * the FIFO timeout interrupt occurred. This must be called
+ * with the port spinlock uap->port.lock held.
+ */
+static void pl011_dma_rx_chars(struct uart_amba_port *uap,
+ u32 pending, bool use_buf_b,
+ bool readfifo)
+{
+ struct tty_struct *tty = uap->port.state->port.tty;
+ struct pl011_sgbuf *sgbuf = use_buf_b ?
+ &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
+ struct device *dev = uap->dmarx.chan->device->dev;
+ int dma_count = 0;
+ u32 fifotaken = 0; /* only used for vdbg() */
+
+ /* Pick everything from the DMA first */
+ if (pending) {
+ /* Sync in buffer */
+ dma_sync_sg_for_cpu(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
+
+ /*
+ * First take all chars in the DMA pipe, then look in the FIFO.
+ * Note that tty_insert_flip_buf() tries to take as many chars
+ * as it can.
+ */
+ dma_count = tty_insert_flip_string(uap->port.state->port.tty,
+ sgbuf->buf, pending);
+
+ /* Return buffer to device */
+ dma_sync_sg_for_device(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
+
+ uap->port.icount.rx += dma_count;
+ if (dma_count < pending)
+ dev_warn(uap->port.dev,
+ "couldn't insert all characters (TTY is full?)\n");
+ }
+
+ /*
+ * Only continue with trying to read the FIFO if all DMA chars have
+ * been taken first.
+ */
+ if (dma_count == pending && readfifo) {
+ /* Clear any error flags */
+ writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS,
+ uap->port.membase + UART011_ICR);
+
+ /*
+ * If we read all the DMA'd characters, and we had an
+ * incomplete buffer, that could be due to an rx error, or
+ * maybe we just timed out. Read any pending chars and check
+ * the error status.
+ *
+ * Error conditions will only occur in the FIFO, these will
+ * trigger an immediate interrupt and stop the DMA job, so we
+ * will always find the error in the FIFO, never in the DMA
+ * buffer.
+ */
+ fifotaken = pl011_fifo_to_tty(uap);
+ }
+
+ spin_unlock(&uap->port.lock);
+ dev_vdbg(uap->port.dev,
+ "Took %d chars from DMA buffer and %d chars from the FIFO\n",
+ dma_count, fifotaken);
+ tty_flip_buffer_push(tty);
+ spin_lock(&uap->port.lock);
+}
+
+static void pl011_dma_rx_irq(struct uart_amba_port *uap)
+{
+ struct pl011_dmarx_data *dmarx = &uap->dmarx;
+ struct dma_chan *rxchan = dmarx->chan;
+ struct pl011_sgbuf *sgbuf = dmarx->use_buf_b ?
+ &dmarx->sgbuf_b : &dmarx->sgbuf_a;
+ size_t pending;
+ struct dma_tx_state state;
+ enum dma_status dmastat;
+
+ /*
+ * Pause the transfer so we can trust the current counter,
+ * do this before we pause the PL011 block, else we may
+ * overflow the FIFO.
+ */
+ if (dmaengine_pause(rxchan))
+ dev_err(uap->port.dev, "unable to pause DMA transfer\n");
+ dmastat = rxchan->device->device_tx_status(rxchan,
+ dmarx->cookie, &state);
+ if (dmastat != DMA_PAUSED)
+ dev_err(uap->port.dev, "unable to pause DMA transfer\n");
+
+ /* Disable RX DMA - incoming data will wait in the FIFO */
+ uap->dmacr &= ~UART011_RXDMAE;
+ writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+ uap->dmarx.running = false;
+
+ pending = sgbuf->sg.length - state.residue;
+ BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
+ /* Then we terminate the transfer - we now know our residue */
+ dmaengine_terminate_all(rxchan);
+
+ /*
+ * This will take the chars we have so far and insert
+ * into the framework.
+ */
+ pl011_dma_rx_chars(uap, pending, dmarx->use_buf_b, true);
+
+ /* Switch buffer & re-trigger DMA job */
+ dmarx->use_buf_b = !dmarx->use_buf_b;
+ if (pl011_dma_rx_trigger_dma(uap)) {
+ dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
+ "fall back to interrupt mode\n");
+ uap->im |= UART011_RXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ }
+}
+
+static void pl011_dma_rx_callback(void *data)
+{
+ struct uart_amba_port *uap = data;
+ struct pl011_dmarx_data *dmarx = &uap->dmarx;
+ bool lastbuf = dmarx->use_buf_b;
+ int ret;
+
+ /*
+ * This completion interrupt occurs typically when the
+ * RX buffer is totally stuffed but no timeout has yet
+ * occurred. When that happens, we just want the RX
+ * routine to flush out the secondary DMA buffer while
+ * we immediately trigger the next DMA job.
+ */
+ spin_lock_irq(&uap->port.lock);
+ uap->dmarx.running = false;
+ dmarx->use_buf_b = !lastbuf;
+ ret = pl011_dma_rx_trigger_dma(uap);
+
+ pl011_dma_rx_chars(uap, PL011_DMA_BUFFER_SIZE, lastbuf, false);
+ spin_unlock_irq(&uap->port.lock);
+ /*
+ * Do this check after we picked the DMA chars so we don't
+ * get some IRQ immediately from RX.
+ */
+ if (ret) {
+ dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
+ "fall back to interrupt mode\n");
+ uap->im |= UART011_RXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ }
+}
+
+/*
+ * Stop accepting received characters, when we're shutting down or
+ * suspending this port.
+ * Locking: called with port lock held and IRQs disabled.
+ */
+static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
+{
+ /* FIXME. Just disable the DMA enable */
+ uap->dmacr &= ~UART011_RXDMAE;
+ writew(uap->dmacr, uap->port.membase + UART011_DMACR);
+}
static void pl011_dma_startup(struct uart_amba_port *uap)
{
+ int ret;
+
if (!uap->dmatx.chan)
return;
@@ -525,8 +857,33 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
/* The DMA buffer is now the FIFO the TTY subsystem can use */
uap->port.fifosize = PL011_DMA_BUFFER_SIZE;
- uap->using_dma = true;
+ uap->using_tx_dma = true;
+
+ if (!uap->dmarx.chan)
+ goto skip_rx;
+
+ /* Allocate and map DMA RX buffers */
+ ret = pl011_sgbuf_init(uap->dmarx.chan, &uap->dmarx.sgbuf_a,
+ DMA_FROM_DEVICE);
+ if (ret) {
+ dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
+ "RX buffer A", ret);
+ goto skip_rx;
+ }
+
+ ret = pl011_sgbuf_init(uap->dmarx.chan, &uap->dmarx.sgbuf_b,
+ DMA_FROM_DEVICE);
+ if (ret) {
+ dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
+ "RX buffer B", ret);
+ pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a,
+ DMA_FROM_DEVICE);
+ goto skip_rx;
+ }
+ uap->using_rx_dma = true;
+
+skip_rx:
/* Turn on DMA error (RX/TX will be enabled on demand) */
uap->dmacr |= UART011_DMAONERR;
writew(uap->dmacr, uap->port.membase + UART011_DMACR);
@@ -539,11 +896,17 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
if (uap->vendor->dma_threshold)
writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16,
uap->port.membase + ST_UART011_DMAWM);
+
+ if (uap->using_rx_dma) {
+ if (pl011_dma_rx_trigger_dma(uap))
+ dev_dbg(uap->port.dev, "could not trigger initial "
+ "RX DMA job, fall back to interrupt mode\n");
+ }
}
static void pl011_dma_shutdown(struct uart_amba_port *uap)
{
- if (!uap->using_dma)
+ if (!(uap->using_tx_dma || uap->using_rx_dma))
return;
/* Disable RX and TX DMA */
@@ -555,19 +918,39 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
writew(uap->dmacr, uap->port.membase + UART011_DMACR);
spin_unlock_irq(&uap->port.lock);
- /* In theory, this should already be done by pl011_dma_flush_buffer */
- dmaengine_terminate_all(uap->dmatx.chan);
- if (uap->dmatx.queued) {
- dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
- DMA_TO_DEVICE);
- uap->dmatx.queued = false;
+ if (uap->using_tx_dma) {
+ /* In theory, this should already be done by pl011_dma_flush_buffer */
+ dmaengine_terminate_all(uap->dmatx.chan);
+ if (uap->dmatx.queued) {
+ dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1,
+ DMA_TO_DEVICE);
+ uap->dmatx.queued = false;
+ }
+
+ kfree(uap->dmatx.buf);
+ uap->using_tx_dma = false;
}
- kfree(uap->dmatx.buf);
+ if (uap->using_rx_dma) {
+ dmaengine_terminate_all(uap->dmarx.chan);
+ /* Clean up the RX DMA */
+ pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a, DMA_FROM_DEVICE);
+ pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_b, DMA_FROM_DEVICE);
+ uap->using_rx_dma = false;
+ }
+}
- uap->using_dma = false;
+static inline bool pl011_dma_rx_available(struct uart_amba_port *uap)
+{
+ return uap->using_rx_dma;
}
+static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
+{
+ return uap->using_rx_dma && uap->dmarx.running;
+}
+
+
#else
/* Blank functions if the DMA engine is not available */
static inline void pl011_dma_probe(struct uart_amba_port *uap)
@@ -600,6 +983,29 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
return false;
}
+static inline void pl011_dma_rx_irq(struct uart_amba_port *uap)
+{
+}
+
+static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
+{
+}
+
+static inline int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
+{
+ return -EIO;
+}
+
+static inline bool pl011_dma_rx_available(struct uart_amba_port *uap)
+{
+ return false;
+}
+
+static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
+{
+ return false;
+}
+
#define pl011_dma_flush_buffer NULL
#endif
@@ -630,6 +1036,8 @@ static void pl011_stop_rx(struct uart_port *port)
uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
UART011_PEIM|UART011_BEIM|UART011_OEIM);
writew(uap->im, uap->port.membase + UART011_IMSC);
+
+ pl011_dma_rx_stop(uap);
}
static void pl011_enable_ms(struct uart_port *port)
@@ -643,51 +1051,24 @@ static void pl011_enable_ms(struct uart_port *port)
static void pl011_rx_chars(struct uart_amba_port *uap)
{
struct tty_struct *tty = uap->port.state->port.tty;
- unsigned int status, ch, flag, max_count = 256;
-
- status = readw(uap->port.membase + UART01x_FR);
- while ((status & UART01x_FR_RXFE) == 0 && max_count--) {
- ch = readw(uap->port.membase + UART01x_DR) | UART_DUMMY_DR_RX;
- flag = TTY_NORMAL;
- uap->port.icount.rx++;
-
- /*
- * Note that the error handling code is
- * out of the main execution path
- */
- if (unlikely(ch & UART_DR_ERROR)) {
- if (ch & UART011_DR_BE) {
- ch &= ~(UART011_DR_FE | UART011_DR_PE);
- uap->port.icount.brk++;
- if (uart_handle_break(&uap->port))
- goto ignore_char;
- } else if (ch & UART011_DR_PE)
- uap->port.icount.parity++;
- else if (ch & UART011_DR_FE)
- uap->port.icount.frame++;
- if (ch & UART011_DR_OE)
- uap->port.icount.overrun++;
-
- ch &= uap->port.read_status_mask;
-
- if (ch & UART011_DR_BE)
- flag = TTY_BREAK;
- else if (ch & UART011_DR_PE)
- flag = TTY_PARITY;
- else if (ch & UART011_DR_FE)
- flag = TTY_FRAME;
- }
- if (uart_handle_sysrq_char(&uap->port, ch & 255))
- goto ignore_char;
-
- uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
+ pl011_fifo_to_tty(uap);
- ignore_char:
- status = readw(uap->port.membase + UART01x_FR);
- }
spin_unlock(&uap->port.lock);
tty_flip_buffer_push(tty);
+ /*
+ * If we were temporarily out of DMA mode for a while,
+ * attempt to switch back to DMA mode again.
+ */
+ if (pl011_dma_rx_available(uap)) {
+ if (pl011_dma_rx_trigger_dma(uap)) {
+ dev_dbg(uap->port.dev, "could not trigger RX DMA job "
+ "fall back to interrupt mode again\n");
+ uap->im |= UART011_RXIM;
+ } else
+ uap->im &= ~UART011_RXIM;
+ writew(uap->im, uap->port.membase + UART011_IMSC);
+ }
spin_lock(&uap->port.lock);
}
@@ -767,8 +1148,12 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
UART011_RXIS),
uap->port.membase + UART011_ICR);
- if (status & (UART011_RTIS|UART011_RXIS))
- pl011_rx_chars(uap);
+ if (status & (UART011_RTIS|UART011_RXIS)) {
+ if (pl011_dma_rx_running(uap))
+ pl011_dma_rx_irq(uap);
+ else
+ pl011_rx_chars(uap);
+ }
if (status & (UART011_DSRMIS|UART011_DCDMIS|
UART011_CTSMIS|UART011_RIMIS))
pl011_modem_status(uap);
@@ -945,10 +1330,14 @@ static int pl011_startup(struct uart_port *port)
pl011_dma_startup(uap);
/*
- * Finally, enable interrupts
+ * Finally, enable interrupts, only timeouts when using DMA
+ * if initial RX DMA job failed, start in interrupt mode
+ * as well.
*/
spin_lock_irq(&uap->port.lock);
- uap->im = UART011_RXIM | UART011_RTIM;
+ uap->im = UART011_RTIM;
+ if (!pl011_dma_rx_running(uap))
+ uap->im |= UART011_RXIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
spin_unlock_irq(&uap->port.lock);
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
index b62857bf2fd..37e13c3d91d 100644
--- a/drivers/tty/serial/mrst_max3110.c
+++ b/drivers/tty/serial/mrst_max3110.c
@@ -51,7 +51,7 @@
struct uart_max3110 {
struct uart_port port;
struct spi_device *spi;
- char name[24];
+ char name[SPI_NAME_SIZE];
wait_queue_head_t wq;
struct task_struct *main_thread;
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 8e43a7b69e6..bfee9b4c666 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2007 Google, Inc.
* Author: Robert Love <rlove@google.com>
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -31,6 +32,7 @@
#include <linux/serial.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/delay.h>
#include "msm_serial.h"
@@ -38,9 +40,20 @@ struct msm_port {
struct uart_port uart;
char name[16];
struct clk *clk;
+ struct clk *pclk;
unsigned int imr;
+ unsigned int *gsbi_base;
+ int is_uartdm;
+ unsigned int old_snap_state;
};
+static inline void wait_for_xmitr(struct uart_port *port, int bits)
+{
+ if (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY))
+ while ((msm_read(port, UART_ISR) & bits) != bits)
+ cpu_relax();
+}
+
static void msm_stop_tx(struct uart_port *port)
{
struct msm_port *msm_port = UART_TO_MSM(port);
@@ -73,6 +86,61 @@ static void msm_enable_ms(struct uart_port *port)
msm_write(port, msm_port->imr, UART_IMR);
}
+static void handle_rx_dm(struct uart_port *port, unsigned int misr)
+{
+ struct tty_struct *tty = port->state->port.tty;
+ unsigned int sr;
+ int count = 0;
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
+ port->icount.overrun++;
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+ }
+
+ if (misr & UART_IMR_RXSTALE) {
+ count = msm_read(port, UARTDM_RX_TOTAL_SNAP) -
+ msm_port->old_snap_state;
+ msm_port->old_snap_state = 0;
+ } else {
+ count = 4 * (msm_read(port, UART_RFWR));
+ msm_port->old_snap_state += count;
+ }
+
+ /* TODO: Precise error reporting */
+
+ port->icount.rx += count;
+
+ while (count > 0) {
+ unsigned int c;
+
+ sr = msm_read(port, UART_SR);
+ if ((sr & UART_SR_RX_READY) == 0) {
+ msm_port->old_snap_state -= count;
+ break;
+ }
+ c = msm_read(port, UARTDM_RF);
+ if (sr & UART_SR_RX_BREAK) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ } else if (sr & UART_SR_PAR_FRAME_ERR)
+ port->icount.frame++;
+
+ /* TODO: handle sysrq */
+ tty_insert_flip_string(tty, (char *) &c,
+ (count > 4) ? 4 : count);
+ count -= 4;
+ }
+
+ tty_flip_buffer_push(tty);
+ if (misr & (UART_IMR_RXSTALE))
+ msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
+ msm_write(port, 0xFFFFFF, UARTDM_DMRX);
+ msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
+}
+
static void handle_rx(struct uart_port *port)
{
struct tty_struct *tty = port->state->port.tty;
@@ -121,6 +189,12 @@ static void handle_rx(struct uart_port *port)
tty_flip_buffer_push(tty);
}
+static void reset_dm_count(struct uart_port *port)
+{
+ wait_for_xmitr(port, UART_ISR_TX_READY);
+ msm_write(port, 1, UARTDM_NCF_TX);
+}
+
static void handle_tx(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
@@ -128,11 +202,18 @@ static void handle_tx(struct uart_port *port)
int sent_tx;
if (port->x_char) {
- msm_write(port, port->x_char, UART_TF);
+ if (msm_port->is_uartdm)
+ reset_dm_count(port);
+
+ msm_write(port, port->x_char,
+ msm_port->is_uartdm ? UARTDM_TF : UART_TF);
port->icount.tx++;
port->x_char = 0;
}
+ if (msm_port->is_uartdm)
+ reset_dm_count(port);
+
while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
if (uart_circ_empty(xmit)) {
/* disable tx interrupts */
@@ -140,8 +221,11 @@ static void handle_tx(struct uart_port *port)
msm_write(port, msm_port->imr, UART_IMR);
break;
}
+ msm_write(port, xmit->buf[xmit->tail],
+ msm_port->is_uartdm ? UARTDM_TF : UART_TF);
- msm_write(port, xmit->buf[xmit->tail], UART_TF);
+ if (msm_port->is_uartdm)
+ reset_dm_count(port);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
@@ -169,8 +253,12 @@ static irqreturn_t msm_irq(int irq, void *dev_id)
misr = msm_read(port, UART_MISR);
msm_write(port, 0, UART_IMR); /* disable interrupt */
- if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE))
- handle_rx(port);
+ if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) {
+ if (msm_port->is_uartdm)
+ handle_rx_dm(port, misr);
+ else
+ handle_rx(port);
+ }
if (misr & UART_IMR_TXLEV)
handle_tx(port);
if (misr & UART_IMR_DELTA_CTS)
@@ -192,10 +280,21 @@ static unsigned int msm_get_mctrl(struct uart_port *port)
return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
}
-static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
+
+static void msm_reset(struct uart_port *port)
{
- unsigned int mr;
+ /* reset everything */
+ msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
+ msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
+}
+void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ unsigned int mr;
mr = msm_read(port, UART_MR1);
if (!(mctrl & TIOCM_RTS)) {
@@ -219,6 +318,7 @@ static void msm_break_ctl(struct uart_port *port, int break_ctl)
static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
{
unsigned int baud_code, rxstale, watermark;
+ struct msm_port *msm_port = UART_TO_MSM(port);
switch (baud) {
case 300:
@@ -273,6 +373,9 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
break;
}
+ if (msm_port->is_uartdm)
+ msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
+
msm_write(port, baud_code, UART_CSR);
/* RX stale watermark */
@@ -288,25 +391,23 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
/* set TX watermark */
msm_write(port, 10, UART_TFWR);
+ if (msm_port->is_uartdm) {
+ msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
+ msm_write(port, 0xFFFFFF, UARTDM_DMRX);
+ msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
+ }
+
return baud;
}
-static void msm_reset(struct uart_port *port)
-{
- /* reset everything */
- msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
- msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
- msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
- msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
- msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
- msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
-}
static void msm_init_clock(struct uart_port *port)
{
struct msm_port *msm_port = UART_TO_MSM(port);
clk_enable(msm_port->clk);
+ if (!IS_ERR(msm_port->pclk))
+ clk_enable(msm_port->pclk);
msm_serial_set_mnd_regs(port);
}
@@ -347,15 +448,31 @@ static int msm_startup(struct uart_port *port)
msm_write(port, data, UART_IPR);
}
- msm_reset(port);
+ data = 0;
+ if (!port->cons || (port->cons && !(port->cons->flags & CON_ENABLED))) {
+ msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR);
+ msm_reset(port);
+ data = UART_CR_TX_ENABLE;
+ }
+
+ data |= UART_CR_RX_ENABLE;
+ msm_write(port, data, UART_CR); /* enable TX & RX */
- msm_write(port, 0x05, UART_CR); /* enable TX & RX */
+ /* Make sure IPR is not 0 to start with*/
+ if (msm_port->is_uartdm)
+ msm_write(port, UART_IPR_STALE_LSB, UART_IPR);
/* turn on RX and CTS interrupts */
msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE |
UART_IMR_CURRENT_CTS;
- msm_write(port, msm_port->imr, UART_IMR);
+ if (msm_port->is_uartdm) {
+ msm_write(port, 0xFFFFFF, UARTDM_DMRX);
+ msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
+ msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
+ }
+
+ msm_write(port, msm_port->imr, UART_IMR);
return 0;
}
@@ -384,7 +501,7 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
baud = msm_set_baud_rate(port, baud);
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
-
+
/* calculate parity */
mr = msm_read(port, UART_MR2);
mr &= ~UART_MR2_PARITY_MODE;
@@ -454,48 +571,105 @@ static const char *msm_type(struct uart_port *port)
static void msm_release_port(struct uart_port *port)
{
struct platform_device *pdev = to_platform_device(port->dev);
- struct resource *resource;
+ struct msm_port *msm_port = UART_TO_MSM(port);
+ struct resource *uart_resource;
+ struct resource *gsbi_resource;
resource_size_t size;
- resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(!resource))
+ uart_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!uart_resource))
return;
- size = resource->end - resource->start + 1;
+ size = resource_size(uart_resource);
release_mem_region(port->mapbase, size);
iounmap(port->membase);
port->membase = NULL;
+
+ if (msm_port->gsbi_base) {
+ iowrite32(GSBI_PROTOCOL_IDLE, msm_port->gsbi_base +
+ GSBI_CONTROL);
+
+ gsbi_resource = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM,
+ "gsbi_resource");
+
+ if (unlikely(!gsbi_resource))
+ return;
+
+ size = resource_size(gsbi_resource);
+ release_mem_region(gsbi_resource->start, size);
+ iounmap(msm_port->gsbi_base);
+ msm_port->gsbi_base = NULL;
+ }
}
static int msm_request_port(struct uart_port *port)
{
+ struct msm_port *msm_port = UART_TO_MSM(port);
struct platform_device *pdev = to_platform_device(port->dev);
- struct resource *resource;
+ struct resource *uart_resource;
+ struct resource *gsbi_resource;
resource_size_t size;
+ int ret;
- resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(!resource))
+ uart_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "uart_resource");
+ if (unlikely(!uart_resource))
return -ENXIO;
- size = resource->end - resource->start + 1;
- if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial")))
+ size = resource_size(uart_resource);
+
+ if (!request_mem_region(port->mapbase, size, "msm_serial"))
return -EBUSY;
port->membase = ioremap(port->mapbase, size);
if (!port->membase) {
- release_mem_region(port->mapbase, size);
- return -EBUSY;
+ ret = -EBUSY;
+ goto fail_release_port;
+ }
+
+ gsbi_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "gsbi_resource");
+ /* Is this a GSBI-based port? */
+ if (gsbi_resource) {
+ size = resource_size(gsbi_resource);
+
+ if (!request_mem_region(gsbi_resource->start, size,
+ "msm_serial")) {
+ ret = -EBUSY;
+ goto fail_release_port;
+ }
+
+ msm_port->gsbi_base = ioremap(gsbi_resource->start, size);
+ if (!msm_port->gsbi_base) {
+ ret = -EBUSY;
+ goto fail_release_gsbi;
+ }
}
return 0;
+
+fail_release_gsbi:
+ release_mem_region(gsbi_resource->start, size);
+fail_release_port:
+ release_mem_region(port->mapbase, size);
+ return ret;
}
static void msm_config_port(struct uart_port *port, int flags)
{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+ int ret;
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_MSM;
- msm_request_port(port);
+ ret = msm_request_port(port);
+ if (ret)
+ return;
}
+
+ if (msm_port->is_uartdm)
+ iowrite32(GSBI_PROTOCOL_UART, msm_port->gsbi_base +
+ GSBI_CONTROL);
}
static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
@@ -515,9 +689,13 @@ static void msm_power(struct uart_port *port, unsigned int state,
switch (state) {
case 0:
clk_enable(msm_port->clk);
+ if (!IS_ERR(msm_port->pclk))
+ clk_enable(msm_port->pclk);
break;
case 3:
clk_disable(msm_port->clk);
+ if (!IS_ERR(msm_port->pclk))
+ clk_disable(msm_port->pclk);
break;
default:
printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
@@ -550,7 +728,7 @@ static struct msm_port msm_uart_ports[] = {
.iotype = UPIO_MEM,
.ops = &msm_uart_pops,
.flags = UPF_BOOT_AUTOCONF,
- .fifosize = 512,
+ .fifosize = 64,
.line = 0,
},
},
@@ -559,7 +737,7 @@ static struct msm_port msm_uart_ports[] = {
.iotype = UPIO_MEM,
.ops = &msm_uart_pops,
.flags = UPF_BOOT_AUTOCONF,
- .fifosize = 512,
+ .fifosize = 64,
.line = 1,
},
},
@@ -585,9 +763,14 @@ static inline struct uart_port *get_port_from_line(unsigned int line)
static void msm_console_putchar(struct uart_port *port, int c)
{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ if (msm_port->is_uartdm)
+ reset_dm_count(port);
+
while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
;
- msm_write(port, c, UART_TF);
+ msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF);
}
static void msm_console_write(struct console *co, const char *s,
@@ -609,12 +792,14 @@ static void msm_console_write(struct console *co, const char *s,
static int __init msm_console_setup(struct console *co, char *options)
{
struct uart_port *port;
+ struct msm_port *msm_port;
int baud, flow, bits, parity;
if (unlikely(co->index >= UART_NR || co->index < 0))
return -ENXIO;
port = get_port_from_line(co->index);
+ msm_port = UART_TO_MSM(port);
if (unlikely(!port->membase))
return -ENXIO;
@@ -638,6 +823,11 @@ static int __init msm_console_setup(struct console *co, char *options)
msm_reset(port);
+ if (msm_port->is_uartdm) {
+ msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR);
+ msm_write(port, UART_CR_TX_ENABLE, UART_CR);
+ }
+
printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line);
return uart_set_options(port, co, baud, parity, bits, flow);
@@ -685,14 +875,32 @@ static int __init msm_serial_probe(struct platform_device *pdev)
port->dev = &pdev->dev;
msm_port = UART_TO_MSM(port);
- msm_port->clk = clk_get(&pdev->dev, "uart_clk");
- if (IS_ERR(msm_port->clk))
- return PTR_ERR(msm_port->clk);
+ if (platform_get_resource_byname(pdev, IORESOURCE_MEM, "gsbi_resource"))
+ msm_port->is_uartdm = 1;
+ else
+ msm_port->is_uartdm = 0;
+
+ if (msm_port->is_uartdm) {
+ msm_port->clk = clk_get(&pdev->dev, "gsbi_uart_clk");
+ msm_port->pclk = clk_get(&pdev->dev, "gsbi_pclk");
+ } else {
+ msm_port->clk = clk_get(&pdev->dev, "uart_clk");
+ msm_port->pclk = ERR_PTR(-ENOENT);
+ }
+
+ if (unlikely(IS_ERR(msm_port->clk) || (IS_ERR(msm_port->pclk) &&
+ msm_port->is_uartdm)))
+ return PTR_ERR(msm_port->clk);
+
+ if (msm_port->is_uartdm)
+ clk_set_rate(msm_port->clk, 7372800);
+
port->uartclk = clk_get_rate(msm_port->clk);
printk(KERN_INFO "uartclk = %d\n", port->uartclk);
- resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ resource = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "uart_resource");
if (unlikely(!resource))
return -ENXIO;
port->mapbase = resource->start;
diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h
index f6ca9ca79e9..9b8dc5d0d85 100644
--- a/drivers/tty/serial/msm_serial.h
+++ b/drivers/tty/serial/msm_serial.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 2007 Google, Inc.
* Author: Robert Love <rlove@google.com>
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -54,6 +55,7 @@
#define UART_CSR_300 0x22
#define UART_TF 0x000C
+#define UARTDM_TF 0x0070
#define UART_CR 0x0010
#define UART_CR_CMD_NULL (0 << 4)
@@ -64,14 +66,17 @@
#define UART_CR_CMD_START_BREAK (5 << 4)
#define UART_CR_CMD_STOP_BREAK (6 << 4)
#define UART_CR_CMD_RESET_CTS (7 << 4)
+#define UART_CR_CMD_RESET_STALE_INT (8 << 4)
#define UART_CR_CMD_PACKET_MODE (9 << 4)
#define UART_CR_CMD_MODE_RESET (12 << 4)
#define UART_CR_CMD_SET_RFR (13 << 4)
#define UART_CR_CMD_RESET_RFR (14 << 4)
+#define UART_CR_CMD_PROTECTION_EN (16 << 4)
+#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4)
#define UART_CR_TX_DISABLE (1 << 3)
-#define UART_CR_TX_ENABLE (1 << 3)
-#define UART_CR_RX_DISABLE (1 << 3)
-#define UART_CR_RX_ENABLE (1 << 3)
+#define UART_CR_TX_ENABLE (1 << 2)
+#define UART_CR_RX_DISABLE (1 << 1)
+#define UART_CR_RX_ENABLE (1 << 0)
#define UART_IMR 0x0014
#define UART_IMR_TXLEV (1 << 0)
@@ -110,9 +115,20 @@
#define UART_SR_RX_FULL (1 << 1)
#define UART_SR_RX_READY (1 << 0)
-#define UART_RF 0x000C
-#define UART_MISR 0x0010
-#define UART_ISR 0x0014
+#define UART_RF 0x000C
+#define UARTDM_RF 0x0070
+#define UART_MISR 0x0010
+#define UART_ISR 0x0014
+#define UART_ISR_TX_READY (1 << 7)
+
+#define GSBI_CONTROL 0x0
+#define GSBI_PROTOCOL_CODE 0x30
+#define GSBI_PROTOCOL_UART 0x40
+#define GSBI_PROTOCOL_IDLE 0x0
+
+#define UARTDM_DMRX 0x34
+#define UARTDM_NCF_TX 0x40
+#define UARTDM_RX_TOTAL_SNAP 0x38
#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 5c7abe4c94d..6a18ca6ddaa 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -160,17 +160,17 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
* A few common types, add more as needed.
*/
static struct of_device_id __devinitdata of_platform_serial_table[] = {
- { .type = "serial", .compatible = "ns8250", .data = (void *)PORT_8250, },
- { .type = "serial", .compatible = "ns16450", .data = (void *)PORT_16450, },
- { .type = "serial", .compatible = "ns16550a", .data = (void *)PORT_16550A, },
- { .type = "serial", .compatible = "ns16550", .data = (void *)PORT_16550, },
- { .type = "serial", .compatible = "ns16750", .data = (void *)PORT_16750, },
- { .type = "serial", .compatible = "ns16850", .data = (void *)PORT_16850, },
+ { .compatible = "ns8250", .data = (void *)PORT_8250, },
+ { .compatible = "ns16450", .data = (void *)PORT_16450, },
+ { .compatible = "ns16550a", .data = (void *)PORT_16550A, },
+ { .compatible = "ns16550", .data = (void *)PORT_16550, },
+ { .compatible = "ns16750", .data = (void *)PORT_16750, },
+ { .compatible = "ns16850", .data = (void *)PORT_16850, },
#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
- { .type = "serial", .compatible = "ibm,qpace-nwp-serial",
- .data = (void *)PORT_NWPSERIAL, },
+ { .compatible = "ibm,qpace-nwp-serial",
+ .data = (void *)PORT_NWPSERIAL, },
#endif
- { .type = "serial", .data = (void *)PORT_UNKNOWN, },
+ { .type = "serial", .data = (void *)PORT_UNKNOWN, },
{ /* end of list */ },
};
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 7f2f0105878..699b34446a5 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -20,6 +20,10 @@
* this driver as required for the omap-platform.
*/
+#if defined(CONFIG_SERIAL_OMAP_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/console.h>
@@ -190,7 +194,6 @@ static inline void receive_chars(struct uart_omap_port *up, int *status)
if (up->port.line == up->port.cons->index) {
/* Recover the break flag from console xmit */
lsr |= up->lsr_break_flag;
- up->lsr_break_flag = 0;
}
#endif
if (lsr & UART_LSR_BI)