aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStepan Moskovchenko <stepanm@codeaurora.org>2010-12-21 15:38:05 -0500
committerDavid Brown <davidb@codeaurora.org>2011-01-21 18:52:55 -0500
commitec8f29e70edceb93c021148a99a5c3889cdc1b08 (patch)
treef5089d43011477da76ba99c882d601777dbf78b6
parentd41cb8c95681345ded5ef1e78d235d06d68baee2 (diff)
serial: msm: Add support for UARTDM cores
Add support for the next-generation version of the MSM UART to the msm_serial driver. This version of the hardware is similar to the original version, but has some DMA capabilities that are used in PIO mode in this driver. Signed-off-by: Stepan Moskovchenko <stepanm@codeaurora.org> Signed-off-by: David Brown <davidb@codeaurora.org>
-rw-r--r--drivers/serial/msm_serial.c286
-rw-r--r--drivers/serial/msm_serial.h28
2 files changed, 269 insertions, 45 deletions
diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c
index 8e43a7b69e64..bfee9b4c6661 100644
--- a/drivers/serial/msm_serial.c
+++ b/drivers/serial/msm_serial.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright (C) 2007 Google, Inc. 4 * Copyright (C) 2007 Google, Inc.
5 * Author: Robert Love <rlove@google.com> 5 * Author: Robert Love <rlove@google.com>
6 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
6 * 7 *
7 * This software is licensed under the terms of the GNU General Public 8 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and 9 * License version 2, as published by the Free Software Foundation, and
@@ -31,6 +32,7 @@
31#include <linux/serial.h> 32#include <linux/serial.h>
32#include <linux/clk.h> 33#include <linux/clk.h>
33#include <linux/platform_device.h> 34#include <linux/platform_device.h>
35#include <linux/delay.h>
34 36
35#include "msm_serial.h" 37#include "msm_serial.h"
36 38
@@ -38,9 +40,20 @@ struct msm_port {
38 struct uart_port uart; 40 struct uart_port uart;
39 char name[16]; 41 char name[16];
40 struct clk *clk; 42 struct clk *clk;
43 struct clk *pclk;
41 unsigned int imr; 44 unsigned int imr;
45 unsigned int *gsbi_base;
46 int is_uartdm;
47 unsigned int old_snap_state;
42}; 48};
43 49
50static inline void wait_for_xmitr(struct uart_port *port, int bits)
51{
52 if (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY))
53 while ((msm_read(port, UART_ISR) & bits) != bits)
54 cpu_relax();
55}
56
44static void msm_stop_tx(struct uart_port *port) 57static void msm_stop_tx(struct uart_port *port)
45{ 58{
46 struct msm_port *msm_port = UART_TO_MSM(port); 59 struct msm_port *msm_port = UART_TO_MSM(port);
@@ -73,6 +86,61 @@ static void msm_enable_ms(struct uart_port *port)
73 msm_write(port, msm_port->imr, UART_IMR); 86 msm_write(port, msm_port->imr, UART_IMR);
74} 87}
75 88
89static void handle_rx_dm(struct uart_port *port, unsigned int misr)
90{
91 struct tty_struct *tty = port->state->port.tty;
92 unsigned int sr;
93 int count = 0;
94 struct msm_port *msm_port = UART_TO_MSM(port);
95
96 if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
97 port->icount.overrun++;
98 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
99 msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
100 }
101
102 if (misr & UART_IMR_RXSTALE) {
103 count = msm_read(port, UARTDM_RX_TOTAL_SNAP) -
104 msm_port->old_snap_state;
105 msm_port->old_snap_state = 0;
106 } else {
107 count = 4 * (msm_read(port, UART_RFWR));
108 msm_port->old_snap_state += count;
109 }
110
111 /* TODO: Precise error reporting */
112
113 port->icount.rx += count;
114
115 while (count > 0) {
116 unsigned int c;
117
118 sr = msm_read(port, UART_SR);
119 if ((sr & UART_SR_RX_READY) == 0) {
120 msm_port->old_snap_state -= count;
121 break;
122 }
123 c = msm_read(port, UARTDM_RF);
124 if (sr & UART_SR_RX_BREAK) {
125 port->icount.brk++;
126 if (uart_handle_break(port))
127 continue;
128 } else if (sr & UART_SR_PAR_FRAME_ERR)
129 port->icount.frame++;
130
131 /* TODO: handle sysrq */
132 tty_insert_flip_string(tty, (char *) &c,
133 (count > 4) ? 4 : count);
134 count -= 4;
135 }
136
137 tty_flip_buffer_push(tty);
138 if (misr & (UART_IMR_RXSTALE))
139 msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
140 msm_write(port, 0xFFFFFF, UARTDM_DMRX);
141 msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
142}
143
76static void handle_rx(struct uart_port *port) 144static void handle_rx(struct uart_port *port)
77{ 145{
78 struct tty_struct *tty = port->state->port.tty; 146 struct tty_struct *tty = port->state->port.tty;
@@ -121,6 +189,12 @@ static void handle_rx(struct uart_port *port)
121 tty_flip_buffer_push(tty); 189 tty_flip_buffer_push(tty);
122} 190}
123 191
192static void reset_dm_count(struct uart_port *port)
193{
194 wait_for_xmitr(port, UART_ISR_TX_READY);
195 msm_write(port, 1, UARTDM_NCF_TX);
196}
197
124static void handle_tx(struct uart_port *port) 198static void handle_tx(struct uart_port *port)
125{ 199{
126 struct circ_buf *xmit = &port->state->xmit; 200 struct circ_buf *xmit = &port->state->xmit;
@@ -128,11 +202,18 @@ static void handle_tx(struct uart_port *port)
128 int sent_tx; 202 int sent_tx;
129 203
130 if (port->x_char) { 204 if (port->x_char) {
131 msm_write(port, port->x_char, UART_TF); 205 if (msm_port->is_uartdm)
206 reset_dm_count(port);
207
208 msm_write(port, port->x_char,
209 msm_port->is_uartdm ? UARTDM_TF : UART_TF);
132 port->icount.tx++; 210 port->icount.tx++;
133 port->x_char = 0; 211 port->x_char = 0;
134 } 212 }
135 213
214 if (msm_port->is_uartdm)
215 reset_dm_count(port);
216
136 while (msm_read(port, UART_SR) & UART_SR_TX_READY) { 217 while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
137 if (uart_circ_empty(xmit)) { 218 if (uart_circ_empty(xmit)) {
138 /* disable tx interrupts */ 219 /* disable tx interrupts */
@@ -140,8 +221,11 @@ static void handle_tx(struct uart_port *port)
140 msm_write(port, msm_port->imr, UART_IMR); 221 msm_write(port, msm_port->imr, UART_IMR);
141 break; 222 break;
142 } 223 }
224 msm_write(port, xmit->buf[xmit->tail],
225 msm_port->is_uartdm ? UARTDM_TF : UART_TF);
143 226
144 msm_write(port, xmit->buf[xmit->tail], UART_TF); 227 if (msm_port->is_uartdm)
228 reset_dm_count(port);
145 229
146 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 230 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
147 port->icount.tx++; 231 port->icount.tx++;
@@ -169,8 +253,12 @@ static irqreturn_t msm_irq(int irq, void *dev_id)
169 misr = msm_read(port, UART_MISR); 253 misr = msm_read(port, UART_MISR);
170 msm_write(port, 0, UART_IMR); /* disable interrupt */ 254 msm_write(port, 0, UART_IMR); /* disable interrupt */
171 255
172 if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) 256 if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) {
173 handle_rx(port); 257 if (msm_port->is_uartdm)
258 handle_rx_dm(port, misr);
259 else
260 handle_rx(port);
261 }
174 if (misr & UART_IMR_TXLEV) 262 if (misr & UART_IMR_TXLEV)
175 handle_tx(port); 263 handle_tx(port);
176 if (misr & UART_IMR_DELTA_CTS) 264 if (misr & UART_IMR_DELTA_CTS)
@@ -192,10 +280,21 @@ static unsigned int msm_get_mctrl(struct uart_port *port)
192 return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS; 280 return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
193} 281}
194 282
195static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl) 283
284static void msm_reset(struct uart_port *port)
196{ 285{