blob: ca9ceaa113a24b3d685e67c5da1c8bb2bfaf3f77 [file] [log] [blame]
Bryan Wu194de562007-05-06 14:50:30 -07001/*
2 * File: drivers/serial/bfin_5xx.c
3 * Based on: Based on drivers/serial/sa1100.c
4 * Author: Aubrey Li <aubrey.li@analog.com>
5 *
6 * Created:
7 * Description: Driver for blackfin 5xx serial ports
8 *
Bryan Wu194de562007-05-06 14:50:30 -07009 * Modified:
10 * Copyright 2006 Analog Devices Inc.
11 *
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see the file COPYING, or write
26 * to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 */
29
30#if defined(CONFIG_SERIAL_BFIN_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
31#define SUPPORT_SYSRQ
32#endif
33
34#include <linux/module.h>
35#include <linux/ioport.h>
36#include <linux/init.h>
37#include <linux/console.h>
38#include <linux/sysrq.h>
39#include <linux/platform_device.h>
40#include <linux/tty.h>
41#include <linux/tty_flip.h>
42#include <linux/serial_core.h>
43
Sonic Zhang474f1a62007-06-29 16:35:17 +080044#ifdef CONFIG_KGDB_UART
45#include <linux/kgdb.h>
46#include <asm/irq_regs.h>
47#endif
48
Bryan Wu194de562007-05-06 14:50:30 -070049#include <asm/gpio.h>
50#include <asm/mach/bfin_serial_5xx.h>
51
52#ifdef CONFIG_SERIAL_BFIN_DMA
53#include <linux/dma-mapping.h>
54#include <asm/io.h>
55#include <asm/irq.h>
56#include <asm/cacheflush.h>
57#endif
58
59/* UART name and device definitions */
60#define BFIN_SERIAL_NAME "ttyBF"
61#define BFIN_SERIAL_MAJOR 204
62#define BFIN_SERIAL_MINOR 64
63
64/*
65 * Setup for console. Argument comes from the menuconfig
66 */
67#define DMA_RX_XCOUNT 512
68#define DMA_RX_YCOUNT (PAGE_SIZE / DMA_RX_XCOUNT)
69
70#define DMA_RX_FLUSH_JIFFIES 5
71
72#ifdef CONFIG_SERIAL_BFIN_DMA
73static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
74#else
75static void bfin_serial_do_work(struct work_struct *work);
76static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
Bryan Wu194de562007-05-06 14:50:30 -070077#endif
78
79static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);
80
81/*
82 * interrupts are disabled on entry
83 */
84static void bfin_serial_stop_tx(struct uart_port *port)
85{
86 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
Sonic Zhang1b733512007-12-21 16:45:12 +080087#if !defined(CONFIG_BF54x) && !defined(CONFIG_SERIAL_BFIN_DMA)
Sonic Zhang759eb042007-11-21 17:00:32 +080088 unsigned short ier;
89#endif
Bryan Wu194de562007-05-06 14:50:30 -070090
Roy Huangf4d640c92007-07-12 16:43:46 +080091 while (!(UART_GET_LSR(uart) & TEMT))
92 continue;
Roy Huangf4d640c92007-07-12 16:43:46 +080093
Bryan Wu194de562007-05-06 14:50:30 -070094#ifdef CONFIG_SERIAL_BFIN_DMA
95 disable_dma(uart->tx_dma_channel);
96#else
Roy Huangf4d640c92007-07-12 16:43:46 +080097#ifdef CONFIG_BF54x
Roy Huangf4d640c92007-07-12 16:43:46 +080098 /* Clear TFI bit */
99 UART_PUT_LSR(uart, TFI);
100 UART_CLEAR_IER(uart, ETBEI);
101#else
Bryan Wu194de562007-05-06 14:50:30 -0700102 ier = UART_GET_IER(uart);
103 ier &= ~ETBEI;
104 UART_PUT_IER(uart, ier);
105#endif
Roy Huangf4d640c92007-07-12 16:43:46 +0800106#endif
Bryan Wu194de562007-05-06 14:50:30 -0700107}
108
109/*
110 * port is locked and interrupts are disabled
111 */
112static void bfin_serial_start_tx(struct uart_port *port)
113{
114 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
115
116#ifdef CONFIG_SERIAL_BFIN_DMA
117 bfin_serial_dma_tx_chars(uart);
118#else
Roy Huangf4d640c92007-07-12 16:43:46 +0800119#ifdef CONFIG_BF54x
120 UART_SET_IER(uart, ETBEI);
121#else
Bryan Wu194de562007-05-06 14:50:30 -0700122 unsigned short ier;
123 ier = UART_GET_IER(uart);
124 ier |= ETBEI;
125 UART_PUT_IER(uart, ier);
Bryan Wu194de562007-05-06 14:50:30 -0700126#endif
Sonic Zhanga359cca2007-10-10 16:47:58 +0800127 bfin_serial_tx_chars(uart);
Roy Huangf4d640c92007-07-12 16:43:46 +0800128#endif
Bryan Wu194de562007-05-06 14:50:30 -0700129}
130
131/*
132 * Interrupts are enabled
133 */
134static void bfin_serial_stop_rx(struct uart_port *port)
135{
136 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
Sonic Zhanga359cca2007-10-10 16:47:58 +0800137#ifdef CONFIG_KGDB_UART
138 if (uart->port.line != CONFIG_KGDB_UART_PORT) {
139#endif
Roy Huangf4d640c92007-07-12 16:43:46 +0800140#ifdef CONFIG_BF54x
141 UART_CLEAR_IER(uart, ERBFI);
142#else
Bryan Wu194de562007-05-06 14:50:30 -0700143 unsigned short ier;
144
145 ier = UART_GET_IER(uart);
146 ier &= ~ERBFI;
147 UART_PUT_IER(uart, ier);
Roy Huangf4d640c92007-07-12 16:43:46 +0800148#endif
Sonic Zhanga359cca2007-10-10 16:47:58 +0800149#ifdef CONFIG_KGDB_UART
150 }
151#endif
Bryan Wu194de562007-05-06 14:50:30 -0700152}
153
154/*
155 * Set the modem control timer to fire immediately.
156 */
157static void bfin_serial_enable_ms(struct uart_port *port)
158{
159}
160
Sonic Zhang474f1a62007-06-29 16:35:17 +0800161#ifdef CONFIG_KGDB_UART
162static int kgdb_entry_state;
163
164void kgdb_put_debug_char(int chr)
165{
166 struct bfin_serial_port *uart;
167
168 if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS)
169 uart = &bfin_serial_ports[0];
170 else
171 uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
172
173 while (!(UART_GET_LSR(uart) & THRE)) {
Mike Frysingerd5148ff2007-07-25 11:57:42 +0800174 SSYNC();
Sonic Zhang474f1a62007-06-29 16:35:17 +0800175 }
Sonic Zhanga359cca2007-10-10 16:47:58 +0800176
177#ifndef CONFIG_BF54x
Sonic Zhang474f1a62007-06-29 16:35:17 +0800178 UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));
Mike Frysingerd5148ff2007-07-25 11:57:42 +0800179 SSYNC();
Sonic Zhanga359cca2007-10-10 16:47:58 +0800180#endif
Sonic Zhang474f1a62007-06-29 16:35:17 +0800181 UART_PUT_CHAR(uart, (unsigned char)chr);
Mike Frysingerd5148ff2007-07-25 11:57:42 +0800182 SSYNC();
Sonic Zhang474f1a62007-06-29 16:35:17 +0800183}
184
185int kgdb_get_debug_char(void)
186{
187 struct bfin_serial_port *uart;
188 unsigned char chr;
189
190 if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS)
191 uart = &bfin_serial_ports[0];
192 else
193 uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
194
195 while(!(UART_GET_LSR(uart) & DR)) {
Mike Frysingerd5148ff2007-07-25 11:57:42 +0800196 SSYNC();
Sonic Zhang474f1a62007-06-29 16:35:17 +0800197 }
Sonic Zhanga359cca2007-10-10 16:47:58 +0800198#ifndef CONFIG_BF54x
Sonic Zhang474f1a62007-06-29 16:35:17 +0800199 UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));
Mike Frysingerd5148ff2007-07-25 11:57:42 +0800200 SSYNC();
Sonic Zhanga359cca2007-10-10 16:47:58 +0800201#endif
Sonic Zhang474f1a62007-06-29 16:35:17 +0800202 chr = UART_GET_CHAR(uart);
Mike Frysingerd5148ff2007-07-25 11:57:42 +0800203 SSYNC();
Sonic Zhang474f1a62007-06-29 16:35:17 +0800204
205 return chr;
206}
207#endif
208
Bryan Wu194de562007-05-06 14:50:30 -0700209#ifdef CONFIG_SERIAL_BFIN_PIO
Bryan Wu194de562007-05-06 14:50:30 -0700210static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
211{
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800212 struct tty_struct *tty = uart->port.info->tty;
Bryan Wu194de562007-05-06 14:50:30 -0700213 unsigned int status, ch, flg;
Mike Frysingerbbf275f2007-08-05 16:48:08 +0800214 static int in_break = 0;
Sonic Zhang474f1a62007-06-29 16:35:17 +0800215#ifdef CONFIG_KGDB_UART
216 struct pt_regs *regs = get_irq_regs();
217#endif
Bryan Wu194de562007-05-06 14:50:30 -0700218
Bryan Wu194de562007-05-06 14:50:30 -0700219 ch = UART_GET_CHAR(uart);
Sonic Zhang759eb042007-11-21 17:00:32 +0800220 status = UART_GET_LSR(uart);
Bryan Wu194de562007-05-06 14:50:30 -0700221 uart->port.icount.rx++;
222
Sonic Zhang474f1a62007-06-29 16:35:17 +0800223#ifdef CONFIG_KGDB_UART
224 if (uart->port.line == CONFIG_KGDB_UART_PORT) {
225 if (uart->port.cons->index == CONFIG_KGDB_UART_PORT && ch == 0x1) { /* Ctrl + A */
226 kgdb_breakkey_pressed(regs);
227 return;
228 } else if (kgdb_entry_state == 0 && ch == '$') {/* connection from KGDB */
229 kgdb_entry_state = 1;
230 } else if (kgdb_entry_state == 1 && ch == 'q') {
231 kgdb_entry_state = 0;
232 kgdb_breakkey_pressed(regs);
233 return;
234 } else if (ch == 0x3) {/* Ctrl + C */
235 kgdb_entry_state = 0;
236 kgdb_breakkey_pressed(regs);
237 return;
238 } else {
239 kgdb_entry_state = 0;
240 }
241 }
242#endif
Mike Frysingerbbf275f2007-08-05 16:48:08 +0800243
244 if (ANOMALY_05000230) {
245 /* The BF533 family of processors have a nice misbehavior where
246 * they continuously generate characters for a "single" break.
247 * We have to basically ignore this flood until the "next" valid
248 * character comes across. All other Blackfin families operate
249 * properly though.
250 * Note: While Anomaly 05000230 does not directly address this,
251 * the changes that went in for it also fixed this issue.
252 */
253 if (in_break) {
254 if (ch != 0) {
255 in_break = 0;
256 ch = UART_GET_CHAR(uart);
257 if (bfin_revid() < 5)
258 return;
259 } else
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800260 return;
Mike Frysingerbbf275f2007-08-05 16:48:08 +0800261 }
Bryan Wu194de562007-05-06 14:50:30 -0700262 }
Bryan Wu194de562007-05-06 14:50:30 -0700263
264 if (status & BI) {
Mike Frysingerbbf275f2007-08-05 16:48:08 +0800265 if (ANOMALY_05000230)
266 in_break = 1;
Bryan Wu194de562007-05-06 14:50:30 -0700267 uart->port.icount.brk++;
268 if (uart_handle_break(&uart->port))
269 goto ignore_char;
Mike Frysinger98089012007-06-11 15:31:30 +0800270 status &= ~(PE | FE);
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800271 }
272 if (status & PE)
Bryan Wu194de562007-05-06 14:50:30 -0700273 uart->port.icount.parity++;
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800274 if (status & OE)
Bryan Wu194de562007-05-06 14:50:30 -0700275 uart->port.icount.overrun++;
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800276 if (status & FE)
Bryan Wu194de562007-05-06 14:50:30 -0700277 uart->port.icount.frame++;
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800278
279 status &= uart->port.read_status_mask;
280
281 if (status & BI)
282 flg = TTY_BREAK;
283 else if (status & PE)
284 flg = TTY_PARITY;
285 else if (status & FE)
286 flg = TTY_FRAME;
287 else
Bryan Wu194de562007-05-06 14:50:30 -0700288 flg = TTY_NORMAL;
289
290 if (uart_handle_sysrq_char(&uart->port, ch))
291 goto ignore_char;
Bryan Wu194de562007-05-06 14:50:30 -0700292
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800293 uart_insert_char(&uart->port, status, OE, ch, flg);
294
295 ignore_char:
296 tty_flip_buffer_push(tty);
Bryan Wu194de562007-05-06 14:50:30 -0700297}
298
299static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
300{
301 struct circ_buf *xmit = &uart->port.info->xmit;
302
303 if (uart->port.x_char) {
304 UART_PUT_CHAR(uart, uart->port.x_char);
305 uart->port.icount.tx++;
306 uart->port.x_char = 0;
Bryan Wu194de562007-05-06 14:50:30 -0700307 }
308 /*
309 * Check the modem control lines before
310 * transmitting anything.
311 */
312 bfin_serial_mctrl_check(uart);
313
314 if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
315 bfin_serial_stop_tx(&uart->port);
316 return;
317 }
318
Sonic Zhang759eb042007-11-21 17:00:32 +0800319 while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) {
320 UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);
321 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
322 uart->port.icount.tx++;
323 SSYNC();
324 }
Bryan Wu194de562007-05-06 14:50:30 -0700325
326 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
327 uart_write_wakeup(&uart->port);
328
329 if (uart_circ_empty(xmit))
330 bfin_serial_stop_tx(&uart->port);
331}
332
Aubrey Li5c4e4722007-05-21 18:09:38 +0800333static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
334{
335 struct bfin_serial_port *uart = dev_id;
336
Roy Huangf4d640c92007-07-12 16:43:46 +0800337 spin_lock(&uart->port.lock);
Sonic Zhang759eb042007-11-21 17:00:32 +0800338 while ((UART_GET_IER(uart) & ERBFI) && (UART_GET_LSR(uart) & DR))
Aubrey Li5c4e4722007-05-21 18:09:38 +0800339 bfin_serial_rx_chars(uart);
340 spin_unlock(&uart->port.lock);
Sonic Zhang759eb042007-11-21 17:00:32 +0800341
Aubrey Li5c4e4722007-05-21 18:09:38 +0800342 return IRQ_HANDLED;
343}
344
345static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
Bryan Wu194de562007-05-06 14:50:30 -0700346{
347 struct bfin_serial_port *uart = dev_id;
Bryan Wu194de562007-05-06 14:50:30 -0700348
Roy Huangf4d640c92007-07-12 16:43:46 +0800349 spin_lock(&uart->port.lock);
Sonic Zhang759eb042007-11-21 17:00:32 +0800350 if ((UART_GET_IER(uart) & ETBEI) && (UART_GET_LSR(uart) & THRE))
Aubrey Li5c4e4722007-05-21 18:09:38 +0800351 bfin_serial_tx_chars(uart);
Bryan Wu194de562007-05-06 14:50:30 -0700352 spin_unlock(&uart->port.lock);
Sonic Zhang759eb042007-11-21 17:00:32 +0800353
Bryan Wu194de562007-05-06 14:50:30 -0700354 return IRQ_HANDLED;
355}
356
Aubrey Li5c4e4722007-05-21 18:09:38 +0800357
Bryan Wu194de562007-05-06 14:50:30 -0700358static void bfin_serial_do_work(struct work_struct *work)
359{
360 struct bfin_serial_port *uart = container_of(work, struct bfin_serial_port, cts_workqueue);
361
362 bfin_serial_mctrl_check(uart);
363}
Bryan Wu194de562007-05-06 14:50:30 -0700364#endif
365
366#ifdef CONFIG_SERIAL_BFIN_DMA
367static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
368{
369 struct circ_buf *xmit = &uart->port.info->xmit;
370 unsigned short ier;
371 int flags = 0;
372
373 if (!uart->tx_done)
374 return;
Bryan Wu194de562007-05-06 14:50:30 -0700375 uart->tx_done = 0;
376
Bryan Wu194de562007-05-06 14:50:30 -0700377 if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
378 bfin_serial_stop_tx(&uart->port);
379 uart->tx_done = 1;
380 return;
381 }
382
Sonic Zhang1b733512007-12-21 16:45:12 +0800383 if (uart->port.x_char) {
384 UART_PUT_CHAR(uart, uart->port.x_char);
385 uart->port.icount.tx++;
386 uart->port.x_char = 0;
387 }
388
389 /*
390 * Check the modem control lines before
391 * transmitting anything.
392 */
393 bfin_serial_mctrl_check(uart);
394
Bryan Wu194de562007-05-06 14:50:30 -0700395 spin_lock_irqsave(&uart->port.lock, flags);
396 uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
397 if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
398 uart->tx_count = UART_XMIT_SIZE - xmit->tail;
399 blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail),
400 (unsigned long)(xmit->buf+xmit->tail+uart->tx_count));
401 set_dma_config(uart->tx_dma_channel,
402 set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
403 INTR_ON_BUF,
404 DIMENSION_LINEAR,
Michael Hennerich2047e402008-01-22 15:29:18 +0800405 DATA_SIZE_8,
406 DMA_SYNC_RESTART));
Bryan Wu194de562007-05-06 14:50:30 -0700407 set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
408 set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
409 set_dma_x_modify(uart->tx_dma_channel, 1);
410 enable_dma(uart->tx_dma_channel);
Sonic Zhang99ee7b52007-12-21 17:12:55 +0800411
412 xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
413 uart->port.icount.tx += uart->tx_count;
414
Roy Huangf4d640c92007-07-12 16:43:46 +0800415#ifdef CONFIG_BF54x
416 UART_SET_IER(uart, ETBEI);
417#else
Bryan Wu194de562007-05-06 14:50:30 -0700418 ier = UART_GET_IER(uart);
419 ier |= ETBEI;
420 UART_PUT_IER(uart, ier);
Roy Huangf4d640c92007-07-12 16:43:46 +0800421#endif
Bryan Wu194de562007-05-06 14:50:30 -0700422 spin_unlock_irqrestore(&uart->port.lock, flags);
423}
424
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800425static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
Bryan Wu194de562007-05-06 14:50:30 -0700426{
427 struct tty_struct *tty = uart->port.info->tty;
428 int i, flg, status;
429
430 status = UART_GET_LSR(uart);
431 uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);;
432
433 if (status & BI) {
434 uart->port.icount.brk++;
435 if (uart_handle_break(&uart->port))
436 goto dma_ignore_char;
Mike Frysinger98089012007-06-11 15:31:30 +0800437 status &= ~(PE | FE);
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800438 }
439 if (status & PE)
Bryan Wu194de562007-05-06 14:50:30 -0700440 uart->port.icount.parity++;
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800441 if (status & OE)
Bryan Wu194de562007-05-06 14:50:30 -0700442 uart->port.icount.overrun++;
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800443 if (status & FE)
Bryan Wu194de562007-05-06 14:50:30 -0700444 uart->port.icount.frame++;
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800445
446 status &= uart->port.read_status_mask;
447
448 if (status & BI)
449 flg = TTY_BREAK;
450 else if (status & PE)
451 flg = TTY_PARITY;
452 else if (status & FE)
453 flg = TTY_FRAME;
454 else
Bryan Wu194de562007-05-06 14:50:30 -0700455 flg = TTY_NORMAL;
456
457 for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) {
458 if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
459 goto dma_ignore_char;
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800460 uart_insert_char(&uart->port, status, OE, uart->rx_dma_buf.buf[i], flg);
Bryan Wu194de562007-05-06 14:50:30 -0700461 }
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800462
463 dma_ignore_char:
Bryan Wu194de562007-05-06 14:50:30 -0700464 tty_flip_buffer_push(tty);
465}
466
467void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
468{
469 int x_pos, pos;
470 int flags = 0;
471
Bryan Wu194de562007-05-06 14:50:30 -0700472 spin_lock_irqsave(&uart->port.lock, flags);
473 x_pos = DMA_RX_XCOUNT - get_dma_curr_xcount(uart->rx_dma_channel);
474 if (x_pos == DMA_RX_XCOUNT)
475 x_pos = 0;
476
477 pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;
478
479 if (pos>uart->rx_dma_buf.tail) {
480 uart->rx_dma_buf.tail = pos;
481 bfin_serial_dma_rx_chars(uart);
482 uart->rx_dma_buf.head = uart->rx_dma_buf.tail;
483 }
484 spin_unlock_irqrestore(&uart->port.lock, flags);
485 uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
486 add_timer(&(uart->rx_dma_timer));
487}
488
489static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
490{
491 struct bfin_serial_port *uart = dev_id;
492 struct circ_buf *xmit = &uart->port.info->xmit;
493 unsigned short ier;
494
495 spin_lock(&uart->port.lock);
496 if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
497 clear_dma_irqstat(uart->tx_dma_channel);
498 disable_dma(uart->tx_dma_channel);
Roy Huangf4d640c92007-07-12 16:43:46 +0800499#ifdef CONFIG_BF54x
500 UART_CLEAR_IER(uart, ETBEI);
501#else
Bryan Wu194de562007-05-06 14:50:30 -0700502 ier = UART_GET_IER(uart);
503 ier &= ~ETBEI;
504 UART_PUT_IER(uart, ier);
Roy Huangf4d640c92007-07-12 16:43:46 +0800505#endif
Bryan Wu194de562007-05-06 14:50:30 -0700506 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
507 uart_write_wakeup(&uart->port);
508
Bryan Wu194de562007-05-06 14:50:30 -0700509 uart->tx_done = 1;
Sonic Zhang1b733512007-12-21 16:45:12 +0800510
511 bfin_serial_dma_tx_chars(uart);
Bryan Wu194de562007-05-06 14:50:30 -0700512 }
513
514 spin_unlock(&uart->port.lock);
515 return IRQ_HANDLED;
516}
517
518static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
519{
520 struct bfin_serial_port *uart = dev_id;
521 unsigned short irqstat;
522
523 uart->rx_dma_nrows++;
524 if (uart->rx_dma_nrows == DMA_RX_YCOUNT) {
525 uart->rx_dma_nrows = 0;
526 uart->rx_dma_buf.tail = DMA_RX_XCOUNT*DMA_RX_YCOUNT;
527 bfin_serial_dma_rx_chars(uart);
528 uart->rx_dma_buf.head = uart->rx_dma_buf.tail = 0;
529 }
530 spin_lock(&uart->port.lock);
531 irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
532 clear_dma_irqstat(uart->rx_dma_channel);
533
534 spin_unlock(&uart->port.lock);
535 return IRQ_HANDLED;
536}
537#endif
538
539/*
540 * Return TIOCSER_TEMT when transmitter is not busy.
541 */
542static unsigned int bfin_serial_tx_empty(struct uart_port *port)
543{
544 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
545 unsigned short lsr;
546
547 lsr = UART_GET_LSR(uart);
548 if (lsr & TEMT)
549 return TIOCSER_TEMT;
550 else
551 return 0;
552}
553
554static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
555{
556#ifdef CONFIG_SERIAL_BFIN_CTSRTS
557 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
558 if (uart->cts_pin < 0)
559 return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
560
561 if (gpio_get_value(uart->cts_pin))
562 return TIOCM_DSR | TIOCM_CAR;
563 else
564#endif
565 return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
566}
567
568static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
569{
570#ifdef CONFIG_SERIAL_BFIN_CTSRTS
571 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
572 if (uart->rts_pin < 0)
573 return;
574
575 if (mctrl & TIOCM_RTS)
576 gpio_set_value(uart->rts_pin, 0);
577 else
578 gpio_set_value(uart->rts_pin, 1);
579#endif
580}
581
582/*
583 * Handle any change of modem status signal since we were last called.
584 */
585static void bfin_serial_mctrl_check(struct bfin_serial_port *uart)
586{
587#ifdef CONFIG_SERIAL_BFIN_CTSRTS
588 unsigned int status;
589# ifdef CONFIG_SERIAL_BFIN_DMA
590 struct uart_info *info = uart->port.info;
591 struct tty_struct *tty = info->tty;
592
593 status = bfin_serial_get_mctrl(&uart->port);
594 if (!(status & TIOCM_CTS)) {
595 tty->hw_stopped = 1;
596 } else {
597 tty->hw_stopped = 0;
598 }
599# else
600 status = bfin_serial_get_mctrl(&uart->port);
601 uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
602 if (!(status & TIOCM_CTS))
603 schedule_work(&uart->cts_workqueue);
604# endif
605#endif
606}
607
608/*
609 * Interrupts are always disabled.
610 */
611static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
612{
Mike Frysingercf686762007-06-11 16:12:49 +0800613 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
614 u16 lcr = UART_GET_LCR(uart);
615 if (break_state)
616 lcr |= SB;
617 else
618 lcr &= ~SB;
619 UART_PUT_LCR(uart, lcr);
620 SSYNC();
Bryan Wu194de562007-05-06 14:50:30 -0700621}
622
623static int bfin_serial_startup(struct uart_port *port)
624{
625 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
626
627#ifdef CONFIG_SERIAL_BFIN_DMA
628 dma_addr_t dma_handle;
629
630 if (request_dma(uart->rx_dma_channel, "BFIN_UART_RX") < 0) {
631 printk(KERN_NOTICE "Unable to attach Blackfin UART RX DMA channel\n");
632 return -EBUSY;
633 }
634
635 if (request_dma(uart->tx_dma_channel, "BFIN_UART_TX") < 0) {
636 printk(KERN_NOTICE "Unable to attach Blackfin UART TX DMA channel\n");
637 free_dma(uart->rx_dma_channel);
638 return -EBUSY;
639 }
640
641 set_dma_callback(uart->rx_dma_channel, bfin_serial_dma_rx_int, uart);
642 set_dma_callback(uart->tx_dma_channel, bfin_serial_dma_tx_int, uart);
643
644 uart->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA);
645 uart->rx_dma_buf.head = 0;
646 uart->rx_dma_buf.tail = 0;
647 uart->rx_dma_nrows = 0;
648
649 set_dma_config(uart->rx_dma_channel,
650 set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,
651 INTR_ON_ROW, DIMENSION_2D,
Michael Hennerich2047e402008-01-22 15:29:18 +0800652 DATA_SIZE_8,
653 DMA_SYNC_RESTART));
Bryan Wu194de562007-05-06 14:50:30 -0700654 set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT);
655 set_dma_x_modify(uart->rx_dma_channel, 1);
656 set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT);
657 set_dma_y_modify(uart->rx_dma_channel, 1);
658 set_dma_start_addr(uart->rx_dma_channel, (unsigned long)uart->rx_dma_buf.buf);
659 enable_dma(uart->rx_dma_channel);
660
661 uart->rx_dma_timer.data = (unsigned long)(uart);
662 uart->rx_dma_timer.function = (void *)bfin_serial_rx_dma_timeout;
663 uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
664 add_timer(&(uart->rx_dma_timer));
665#else
Sonic Zhanga359cca2007-10-10 16:47:58 +0800666 if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
Bryan Wu194de562007-05-06 14:50:30 -0700667 "BFIN_UART_RX", uart)) {
Sonic Zhanga359cca2007-10-10 16:47:58 +0800668# ifdef CONFIG_KGDB_UART
669 if (uart->port.line != CONFIG_KGDB_UART_PORT) {
670# endif
Bryan Wu194de562007-05-06 14:50:30 -0700671 printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
672 return -EBUSY;
Sonic Zhanga359cca2007-10-10 16:47:58 +0800673# ifdef CONFIG_KGDB_UART
674 }
675# endif
Bryan Wu194de562007-05-06 14:50:30 -0700676 }
677
Sonic Zhanga359cca2007-10-10 16:47:58 +0800678
Bryan Wu194de562007-05-06 14:50:30 -0700679 if (request_irq
Aubrey Li5c4e4722007-05-21 18:09:38 +0800680 (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED,
Bryan Wu194de562007-05-06 14:50:30 -0700681 "BFIN_UART_TX", uart)) {
682 printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n");
683 free_irq(uart->port.irq, uart);
684 return -EBUSY;
685 }
686#endif
Roy Huangf4d640c92007-07-12 16:43:46 +0800687#ifdef CONFIG_BF54x
688 UART_SET_IER(uart, ERBFI);
689#else
Bryan Wu194de562007-05-06 14:50:30 -0700690 UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);
Roy Huangf4d640c92007-07-12 16:43:46 +0800691#endif
Bryan Wu194de562007-05-06 14:50:30 -0700692 return 0;
693}
694
695static void bfin_serial_shutdown(struct uart_port *port)
696{
697 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
698
699#ifdef CONFIG_SERIAL_BFIN_DMA
700 disable_dma(uart->tx_dma_channel);
701 free_dma(uart->tx_dma_channel);
702 disable_dma(uart->rx_dma_channel);
703 free_dma(uart->rx_dma_channel);
704 del_timer(&(uart->rx_dma_timer));
Sonic Zhang75b780b2007-12-21 17:03:39 +0800705 dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0);
Bryan Wu194de562007-05-06 14:50:30 -0700706#else
Sonic Zhang474f1a62007-06-29 16:35:17 +0800707#ifdef CONFIG_KGDB_UART
708 if (uart->port.line != CONFIG_KGDB_UART_PORT)
709#endif
Bryan Wu194de562007-05-06 14:50:30 -0700710 free_irq(uart->port.irq, uart);
711 free_irq(uart->port.irq+1, uart);
712#endif
713}
714
715static void
716bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
717 struct ktermios *old)
718{
719 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
720 unsigned long flags;
721 unsigned int baud, quot;
722 unsigned short val, ier, lsr, lcr = 0;
723
724 switch (termios->c_cflag & CSIZE) {
725 case CS8:
726 lcr = WLS(8);
727 break;
728 case CS7:
729 lcr = WLS(7);
730 break;
731 case CS6:
732 lcr = WLS(6);
733 break;
734 case CS5:
735 lcr = WLS(5);
736 break;
737 default:
738 printk(KERN_ERR "%s: word lengh not supported\n",
739 __FUNCTION__);
740 }
741
742 if (termios->c_cflag & CSTOPB)
743 lcr |= STB;
Mike Frysinger19aa6382007-06-11 16:16:45 +0800744 if (termios->c_cflag & PARENB)
Bryan Wu194de562007-05-06 14:50:30 -0700745 lcr |= PEN;
Mike Frysinger19aa6382007-06-11 16:16:45 +0800746 if (!(termios->c_cflag & PARODD))
747 lcr |= EPS;
748 if (termios->c_cflag & CMSPAR)
749 lcr |= STP;
Bryan Wu194de562007-05-06 14:50:30 -0700750
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800751 port->read_status_mask = OE;
752 if (termios->c_iflag & INPCK)
753 port->read_status_mask |= (FE | PE);
754 if (termios->c_iflag & (BRKINT | PARMRK))
755 port->read_status_mask |= BI;
Bryan Wu194de562007-05-06 14:50:30 -0700756
Mike Frysinger2ac5ee42007-05-21 18:09:39 +0800757 /*
758 * Characters to ignore
759 */
760 port->ignore_status_mask = 0;
761 if (termios->c_iflag & IGNPAR)
762 port->ignore_status_mask |= FE | PE;
763 if (termios->c_iflag & IGNBRK) {
764 port->ignore_status_mask |= BI;
765 /*
766 * If we're ignoring parity and break indicators,
767 * ignore overruns too (for real raw support).
768 */
769 if (termios->c_iflag & IGNPAR)
770 port->ignore_status_mask |= OE;
771 }
Bryan Wu194de562007-05-06 14:50:30 -0700772
773 baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
774 quot = uart_get_divisor(port, baud);
775 spin_lock_irqsave(&uart->port.lock, flags);
776
777 do {
778 lsr = UART_GET_LSR(uart);
779 } while (!(lsr & TEMT));
780
781 /* Disable UART */
782 ier = UART_GET_IER(uart);
Roy Huangf4d640c92007-07-12 16:43:46 +0800783#ifdef CONFIG_BF54x
784 UART_CLEAR_IER(uart, 0xF);
785#else
Bryan Wu194de562007-05-06 14:50:30 -0700786 UART_PUT_IER(uart, 0);
Roy Huangf4d640c92007-07-12 16:43:46 +0800787#endif
Bryan Wu194de562007-05-06 14:50:30 -0700788
Roy Huangf4d640c92007-07-12 16:43:46 +0800789#ifndef CONFIG_BF54x
Bryan Wu194de562007-05-06 14:50:30 -0700790 /* Set DLAB in LCR to Access DLL and DLH */
791 val = UART_GET_LCR(uart);
792 val |= DLAB;
793 UART_PUT_LCR(uart, val);
794 SSYNC();
Roy Huangf4d640c92007-07-12 16:43:46 +0800795#endif
Bryan Wu194de562007-05-06 14:50:30 -0700796
797 UART_PUT_DLL(uart, quot & 0xFF);
798 SSYNC();
799 UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
800 SSYNC();
801
Roy Huangf4d640c92007-07-12 16:43:46 +0800802#ifndef CONFIG_BF54x
Bryan Wu194de562007-05-06 14:50:30 -0700803 /* Clear DLAB in LCR to Access THR RBR IER */
804 val = UART_GET_LCR(uart);
805 val &= ~DLAB;
806 UART_PUT_LCR(uart, val);
807 SSYNC();
Roy Huangf4d640c92007-07-12 16:43:46 +0800808#endif
Bryan Wu194de562007-05-06 14:50:30 -0700809
810 UART_PUT_LCR(uart, lcr);
811
812 /* Enable UART */
Roy Huangf4d640c92007-07-12 16:43:46 +0800813#ifdef CONFIG_BF54x
814 UART_SET_IER(uart, ier);
815#else
Bryan Wu194de562007-05-06 14:50:30 -0700816 UART_PUT_IER(uart, ier);
Roy Huangf4d640c92007-07-12 16:43:46 +0800817#endif
Bryan Wu194de562007-05-06 14:50:30 -0700818
819 val = UART_GET_GCTL(uart);
820 val |= UCEN;
821 UART_PUT_GCTL(uart, val);
822
823 spin_unlock_irqrestore(&uart->port.lock, flags);
824}
825
826static const char *bfin_serial_type(struct uart_port *port)
827{
828 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
829
830 return uart->port.type == PORT_BFIN ? "BFIN-UART" : NULL;
831}
832
833/*
834 * Release the memory region(s) being used by 'port'.
835 */
836static void bfin_serial_release_port(struct uart_port *port)
837{
838}
839
840/*
841 * Request the memory region(s) being used by 'port'.
842 */
843static int bfin_serial_request_port(struct uart_port *port)
844{
845 return 0;
846}
847
848/*
849 * Configure/autoconfigure the port.
850 */
851static void bfin_serial_config_port(struct uart_port *port, int flags)
852{
853 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
854
855 if (flags & UART_CONFIG_TYPE &&
856 bfin_serial_request_port(&uart->port) == 0)
857 uart->port.type = PORT_BFIN;
858}
859
860/*
861 * Verify the new serial_struct (for TIOCSSERIAL).
862 * The only change we allow are to the flags and type, and
863 * even then only between PORT_BFIN and PORT_UNKNOWN
864 */
865static int
866bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
867{
868 return 0;
869}
870
871static struct uart_ops bfin_serial_pops = {
872 .tx_empty = bfin_serial_tx_empty,
873 .set_mctrl = bfin_serial_set_mctrl,
874 .get_mctrl = bfin_serial_get_mctrl,
875 .stop_tx = bfin_serial_stop_tx,
876 .start_tx = bfin_serial_start_tx,
877 .stop_rx = bfin_serial_stop_rx,
878 .enable_ms = bfin_serial_enable_ms,
879 .break_ctl = bfin_serial_break_ctl,
880 .startup = bfin_serial_startup,
881 .shutdown = bfin_serial_shutdown,
882 .set_termios = bfin_serial_set_termios,
883 .type = bfin_serial_type,
884 .release_port = bfin_serial_release_port,
885 .request_port = bfin_serial_request_port,
886 .config_port = bfin_serial_config_port,
887 .verify_port = bfin_serial_verify_port,
888};
889
890static void __init bfin_serial_init_ports(void)
891{
892 static int first = 1;
893 int i;
894
895 if (!first)
896 return;
897 first = 0;
898
899 for (i = 0; i < nr_ports; i++) {
900 bfin_serial_ports[i].port.uartclk = get_sclk();
901 bfin_serial_ports[i].port.ops = &bfin_serial_pops;
902 bfin_serial_ports[i].port.line = i;
903 bfin_serial_ports[i].port.iotype = UPIO_MEM;
904 bfin_serial_ports[i].port.membase =
905 (void __iomem *)bfin_serial_resource[i].uart_base_addr;
906 bfin_serial_ports[i].port.mapbase =
907 bfin_serial_resource[i].uart_base_addr;
908 bfin_serial_ports[i].port.irq =
909 bfin_serial_resource[i].uart_irq;
910 bfin_serial_ports[i].port.flags = UPF_BOOT_AUTOCONF;
911#ifdef CONFIG_SERIAL_BFIN_DMA
912 bfin_serial_ports[i].tx_done = 1;
913 bfin_serial_ports[i].tx_count = 0;
914 bfin_serial_ports[i].tx_dma_channel =
915 bfin_serial_resource[i].uart_tx_dma_channel;
916 bfin_serial_ports[i].rx_dma_channel =
917 bfin_serial_resource[i].uart_rx_dma_channel;
918 init_timer(&(bfin_serial_ports[i].rx_dma_timer));
919#else
920 INIT_WORK(&bfin_serial_ports[i].cts_workqueue, bfin_serial_do_work);
921#endif
922#ifdef CONFIG_SERIAL_BFIN_CTSRTS
923 bfin_serial_ports[i].cts_pin =
924 bfin_serial_resource[i].uart_cts_pin;
925 bfin_serial_ports[i].rts_pin =
926 bfin_serial_resource[i].uart_rts_pin;
927#endif
928 bfin_serial_hw_init(&bfin_serial_ports[i]);
Bryan Wu194de562007-05-06 14:50:30 -0700929 }
Roy Huangf4d640c92007-07-12 16:43:46 +0800930
Bryan Wu194de562007-05-06 14:50:30 -0700931}
932
933#ifdef CONFIG_SERIAL_BFIN_CONSOLE
Bryan Wu194de562007-05-06 14:50:30 -0700934/*
935 * If the port was already initialised (eg, by a boot loader),
936 * try to determine the current setup.
937 */
938static void __init
939bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
940 int *parity, int *bits)
941{
942 unsigned short status;
943
944 status = UART_GET_IER(uart) & (ERBFI | ETBEI);
945 if (status == (ERBFI | ETBEI)) {
946 /* ok, the port was enabled */
947 unsigned short lcr, val;
948 unsigned short dlh, dll;
949
950 lcr = UART_GET_LCR(uart);
951
952 *parity = 'n';
953 if (lcr & PEN) {
954 if (lcr & EPS)
955 *parity = 'e';
956 else
957 *parity = 'o';
958 }
959 switch (lcr & 0x03) {
960 case 0: *bits = 5; break;
961 case 1: *bits = 6; break;
962 case 2: *bits = 7; break;
963 case 3: *bits = 8; break;
964 }
Roy Huangf4d640c92007-07-12 16:43:46 +0800965#ifndef CONFIG_BF54x
Bryan Wu194de562007-05-06 14:50:30 -0700966 /* Set DLAB in LCR to Access DLL and DLH */
967 val = UART_GET_LCR(uart);
968 val |= DLAB;
969 UART_PUT_LCR(uart, val);
Roy Huangf4d640c92007-07-12 16:43:46 +0800970#endif
Bryan Wu194de562007-05-06 14:50:30 -0700971
972 dll = UART_GET_DLL(uart);
973 dlh = UART_GET_DLH(uart);
974
Roy Huangf4d640c92007-07-12 16:43:46 +0800975#ifndef CONFIG_BF54x
Bryan Wu194de562007-05-06 14:50:30 -0700976 /* Clear DLAB in LCR to Access THR RBR IER */
977 val = UART_GET_LCR(uart);
978 val &= ~DLAB;
979 UART_PUT_LCR(uart, val);
Roy Huangf4d640c92007-07-12 16:43:46 +0800980#endif
Bryan Wu194de562007-05-06 14:50:30 -0700981
982 *baud = get_sclk() / (16*(dll | dlh << 8));
983 }
984 pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
985}
Robin Getz0ae53642007-10-09 17:24:49 +0800986#endif
987
988#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
989static struct uart_driver bfin_serial_reg;
Bryan Wu194de562007-05-06 14:50:30 -0700990
991static int __init
992bfin_serial_console_setup(struct console *co, char *options)
993{
994 struct bfin_serial_port *uart;
Robin Getz0ae53642007-10-09 17:24:49 +0800995# ifdef CONFIG_SERIAL_BFIN_CONSOLE
Bryan Wu194de562007-05-06 14:50:30 -0700996 int baud = 57600;
997 int bits = 8;
998 int parity = 'n';
Robin Getz0ae53642007-10-09 17:24:49 +0800999# ifdef CONFIG_SERIAL_BFIN_CTSRTS
Bryan Wu194de562007-05-06 14:50:30 -07001000 int flow = 'r';
Robin Getz0ae53642007-10-09 17:24:49 +08001001# else
Bryan Wu194de562007-05-06 14:50:30 -07001002 int flow = 'n';
Robin Getz0ae53642007-10-09 17:24:49 +08001003# endif
1004# endif
Bryan Wu194de562007-05-06 14:50:30 -07001005
1006 /*
1007 * Check whether an invalid uart number has been specified, and
1008 * if so, search for the first available port that does have
1009 * console support.
1010 */
1011 if (co->index == -1 || co->index >= nr_ports)
1012 co->index = 0;
1013 uart = &bfin_serial_ports[co->index];
1014
Robin Getz0ae53642007-10-09 17:24:49 +08001015# ifdef CONFIG_SERIAL_BFIN_CONSOLE
Bryan Wu194de562007-05-06 14:50:30 -07001016 if (options)
1017 uart_parse_options(options, &baud, &parity, &bits, &flow);
1018 else
1019 bfin_serial_console_get_options(uart, &baud, &parity, &bits);
1020
1021 return uart_set_options(&uart->port, co, baud, parity, bits, flow);
Robin Getz0ae53642007-10-09 17:24:49 +08001022# else
1023 return 0;
1024# endif
1025}
1026#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
1027 defined (CONFIG_EARLY_PRINTK) */
1028
1029#ifdef CONFIG_SERIAL_BFIN_CONSOLE
1030static void bfin_serial_console_putchar(struct uart_port *port, int ch)
1031{
1032 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
1033 while (!(UART_GET_LSR(uart) & THRE))
1034 barrier();
1035 UART_PUT_CHAR(uart, ch);
1036 SSYNC();
Bryan Wu194de562007-05-06 14:50:30 -07001037}
1038
Robin Getz0ae53642007-10-09 17:24:49 +08001039/*
1040 * Interrupts are disabled on entering
1041 */
1042static void
1043bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
1044{
1045 struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
1046 int flags = 0;
1047
1048 spin_lock_irqsave(&uart->port.lock, flags);
1049 uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
1050 spin_unlock_irqrestore(&uart->port.lock, flags);
1051
1052}
1053
Bryan Wu194de562007-05-06 14:50:30 -07001054static struct console bfin_serial_console = {
1055 .name = BFIN_SERIAL_NAME,
1056 .write = bfin_serial_console_write,
1057 .device = uart_console_device,
1058 .setup = bfin_serial_console_setup,
1059 .flags = CON_PRINTBUFFER,
1060 .index = -1,
1061 .data = &bfin_serial_reg,
1062};
1063
1064static int __init bfin_serial_rs_console_init(void)
1065{
1066 bfin_serial_init_ports();
1067 register_console(&bfin_serial_console);
Sonic Zhang474f1a62007-06-29 16:35:17 +08001068#ifdef CONFIG_KGDB_UART
1069 kgdb_entry_state = 0;
1070 init_kgdb_uart();
1071#endif
Bryan Wu194de562007-05-06 14:50:30 -07001072 return 0;
1073}
1074console_initcall(bfin_serial_rs_console_init);
1075
1076#define BFIN_SERIAL_CONSOLE &bfin_serial_console
1077#else
1078#define BFIN_SERIAL_CONSOLE NULL
Robin Getz0ae53642007-10-09 17:24:49 +08001079#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
1080
1081
1082#ifdef CONFIG_EARLY_PRINTK
1083static __init void early_serial_putc(struct uart_port *port, int ch)
1084{
1085 unsigned timeout = 0xffff;
1086 struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
1087
1088 while ((!(UART_GET_LSR(uart) & THRE)) && --timeout)
1089 cpu_relax();
1090 UART_PUT_CHAR(uart, ch);
1091}
1092
1093static __init void early_serial_write(struct console *con, const char *s,
1094 unsigned int n)
1095{
1096 struct bfin_serial_port *uart = &bfin_serial_ports[con->index];
1097 unsigned int i;
1098
1099 for (i = 0; i < n; i++, s++) {
1100 if (*s == '\n')
1101 early_serial_putc(&uart->port, '\r');
1102 early_serial_putc(&uart->port, *s);
1103 }
1104}
1105
1106static struct __init console bfin_early_serial_console = {
1107 .name = "early_BFuart",
1108 .write = early_serial_write,
1109 .device = uart_console_device,
1110 .flags = CON_PRINTBUFFER,
1111 .setup = bfin_serial_console_setup,
1112 .index = -1,
1113 .data = &bfin_serial_reg,
1114};
1115
1116struct console __init *bfin_earlyserial_init(unsigned int port,
1117 unsigned int cflag)
1118{
1119 struct bfin_serial_port *uart;
1120 struct ktermios t;
1121
1122 if (port == -1 || port >= nr_ports)
1123 port = 0;
1124 bfin_serial_init_ports();
1125 bfin_early_serial_console.index = port;
Robin Getz0ae53642007-10-09 17:24:49 +08001126 uart = &bfin_serial_ports[port];
1127 t.c_cflag = cflag;
1128 t.c_iflag = 0;
1129 t.c_oflag = 0;
1130 t.c_lflag = ICANON;
1131 t.c_line = port;
1132 bfin_serial_set_termios(&uart->port, &t, &t);
1133 return &bfin_early_serial_console;
1134}
1135
1136#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
Bryan Wu194de562007-05-06 14:50:30 -07001137
1138static struct uart_driver bfin_serial_reg = {
1139 .owner = THIS_MODULE,
1140 .driver_name = "bfin-uart",
1141 .dev_name = BFIN_SERIAL_NAME,
1142 .major = BFIN_SERIAL_MAJOR,
1143 .minor = BFIN_SERIAL_MINOR,
1144 .nr = NR_PORTS,
1145 .cons = BFIN_SERIAL_CONSOLE,
1146};
1147
1148static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state)
1149{
1150 struct bfin_serial_port *uart = platform_get_drvdata(dev);
1151
1152 if (uart)
1153 uart_suspend_port(&bfin_serial_reg, &uart->port);
1154
1155 return 0;
1156}
1157
1158static int bfin_serial_resume(struct platform_device *dev)
1159{
1160 struct bfin_serial_port *uart = platform_get_drvdata(dev);
1161
1162 if (uart)
1163 uart_resume_port(&bfin_serial_reg, &uart->port);
1164
1165 return 0;
1166}
1167
1168static int bfin_serial_probe(struct platform_device *dev)
1169{
1170 struct resource *res = dev->resource;
1171 int i;
1172
1173 for (i = 0; i < dev->num_resources; i++, res++)
1174 if (res->flags & IORESOURCE_MEM)
1175 break;
1176
1177 if (i < dev->num_resources) {
1178 for (i = 0; i < nr_ports; i++, res++) {
1179 if (bfin_serial_ports[i].port.mapbase != res->start)
1180 continue;
1181 bfin_serial_ports[i].port.dev = &dev->dev;
1182 uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
1183 platform_set_drvdata(dev, &bfin_serial_ports[i]);
1184 }
1185 }
1186
1187 return 0;
1188}
1189
1190static int bfin_serial_remove(struct platform_device *pdev)
1191{
1192 struct bfin_serial_port *uart = platform_get_drvdata(pdev);
1193
1194
1195#ifdef CONFIG_SERIAL_BFIN_CTSRTS
1196 gpio_free(uart->cts_pin);
1197 gpio_free(uart->rts_pin);
1198#endif
1199
1200 platform_set_drvdata(pdev, NULL);
1201
1202 if (uart)
1203 uart_remove_one_port(&bfin_serial_reg, &uart->port);
1204
1205 return 0;
1206}
1207
1208static struct platform_driver bfin_serial_driver = {
1209 .probe = bfin_serial_probe,
1210 .remove = bfin_serial_remove,
1211 .suspend = bfin_serial_suspend,
1212 .resume = bfin_serial_resume,
1213 .driver = {
1214 .name = "bfin-uart",
1215 },
1216};
1217
1218static int __init bfin_serial_init(void)
1219{
1220 int ret;
Sonic Zhang474f1a62007-06-29 16:35:17 +08001221#ifdef CONFIG_KGDB_UART
1222 struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
Sonic Zhanga359cca2007-10-10 16:47:58 +08001223 struct ktermios t;
Sonic Zhang474f1a62007-06-29 16:35:17 +08001224#endif
Bryan Wu194de562007-05-06 14:50:30 -07001225
1226 pr_info("Serial: Blackfin serial driver\n");
1227
1228 bfin_serial_init_ports();
1229
1230 ret = uart_register_driver(&bfin_serial_reg);
1231 if (ret == 0) {
1232 ret = platform_driver_register(&bfin_serial_driver);
1233 if (ret) {
1234 pr_debug("uart register failed\n");
1235 uart_unregister_driver(&bfin_serial_reg);
1236 }
1237 }
Sonic Zhang474f1a62007-06-29 16:35:17 +08001238#ifdef CONFIG_KGDB_UART
1239 if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) {
Sonic Zhanga359cca2007-10-10 16:47:58 +08001240 request_irq(uart->port.irq, bfin_serial_rx_int,
Sonic Zhang474f1a62007-06-29 16:35:17 +08001241 IRQF_DISABLED, "BFIN_UART_RX", uart);
1242 pr_info("Request irq for kgdb uart port\n");
Sonic Zhanga359cca2007-10-10 16:47:58 +08001243#ifdef CONFIG_BF54x
1244 UART_SET_IER(uart, ERBFI);
1245#else
Sonic Zhang474f1a62007-06-29 16:35:17 +08001246 UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);
Sonic Zhanga359cca2007-10-10 16:47:58 +08001247#endif
Mike Frysingerd5148ff2007-07-25 11:57:42 +08001248 SSYNC();
Sonic Zhang474f1a62007-06-29 16:35:17 +08001249 t.c_cflag = CS8|B57600;
1250 t.c_iflag = 0;
1251 t.c_oflag = 0;
1252 t.c_lflag = ICANON;
1253 t.c_line = CONFIG_KGDB_UART_PORT;
1254 bfin_serial_set_termios(&uart->port, &t, &t);
1255 }
1256#endif
Bryan Wu194de562007-05-06 14:50:30 -07001257 return ret;
1258}
1259
1260static void __exit bfin_serial_exit(void)
1261{
1262 platform_driver_unregister(&bfin_serial_driver);
1263 uart_unregister_driver(&bfin_serial_reg);
1264}
1265
1266module_init(bfin_serial_init);
1267module_exit(bfin_serial_exit);
1268
1269MODULE_AUTHOR("Aubrey.Li <aubrey.li@analog.com>");
1270MODULE_DESCRIPTION("Blackfin generic serial port driver");
1271MODULE_LICENSE("GPL");
1272MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR);