aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/apbuart.c
diff options
context:
space:
mode:
authorKristoffer Glembo <kristoffer@gaisler.com>2009-11-04 11:39:46 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-04 11:44:54 -0500
commitd4ac42a582e46d7f86f0acb4253a310423c72c4c (patch)
tree6b62aacf31e0d4f938b4077941a5a1eacdb55d7f /drivers/serial/apbuart.c
parent462265bf494c4f2a2f6e06480590becadecbfea7 (diff)
sparc: Support for GRLIB APBUART serial port
This patch adds support for the APBUART serial port from Aeroflex Gaisler's IP library GRLIB. It is currently used in all LEON3 designs (SPARC V8) but can be used on other platforms as well (which support OF). Signed-off-by: Kristoffer Glembo <kristoffer@gaisler.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/serial/apbuart.c')
-rw-r--r--drivers/serial/apbuart.c710
1 files changed, 710 insertions, 0 deletions
diff --git a/drivers/serial/apbuart.c b/drivers/serial/apbuart.c
new file mode 100644
index 000000000000..8a343045131f
--- /dev/null
+++ b/drivers/serial/apbuart.c
@@ -0,0 +1,710 @@
1/*
2 * Driver for GRLIB serial ports (APBUART)
3 *
4 * Based on linux/drivers/serial/amba.c
5 *
6 * Copyright (C) 2000 Deep Blue Solutions Ltd.
7 * Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>
8 * Copyright (C) 2006 Daniel Hellstrom <daniel@gaisler.com>, Aeroflex Gaisler AB
9 * Copyright (C) 2008 Gilead Kutnick <kutnickg@zin-tech.com>
10 * Copyright (C) 2009 Kristoffer Glembo <kristoffer@gaisler.com>, Aeroflex Gaisler AB
11 */
12
13#if defined(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
14#define SUPPORT_SYSRQ
15#endif
16
17#include <linux/module.h>
18#include <linux/tty.h>
19#include <linux/ioport.h>
20#include <linux/init.h>
21#include <linux/serial.h>
22#include <linux/console.h>
23#include <linux/sysrq.h>
24#include <linux/kthread.h>
25#include <linux/device.h>
26#include <linux/of.h>
27#include <linux/of_device.h>
28#include <linux/platform_device.h>
29#include <linux/io.h>
30#include <linux/serial_core.h>
31#include <asm/irq.h>
32#include <asm/oplib.h>
33
34#include "apbuart.h"
35
36#define SERIAL_APBUART_MAJOR TTY_MAJOR
37#define SERIAL_APBUART_MINOR 64
38#define UART_DUMMY_RSR_RX 0x8000 /* for ignore all read */
39
40static void apbuart_tx_chars(struct uart_port *port);
41
42static void apbuart_stop_tx(struct uart_port *port)
43{
44 unsigned int cr;
45
46 cr = UART_GET_CTRL(port);
47 cr &= ~UART_CTRL_TI;
48 UART_PUT_CTRL(port, cr);
49}
50
51static void apbuart_start_tx(struct uart_port *port)
52{
53 unsigned int cr;
54
55 cr = UART_GET_CTRL(port);
56 cr |= UART_CTRL_TI;
57 UART_PUT_CTRL(port, cr);
58
59 if (UART_GET_STATUS(port) & UART_STATUS_THE)
60 apbuart_tx_chars(port);
61}
62
63static void apbuart_stop_rx(struct uart_port *port)
64{
65 unsigned int cr;
66
67 cr = UART_GET_CTRL(port);
68 cr &= ~(UART_CTRL_RI);
69 UART_PUT_CTRL(port, cr);
70}
71
72static void apbuart_enable_ms(struct uart_port *port)
73{
74 /* No modem status change interrupts for APBUART */
75}
76
77static void apbuart_rx_chars(struct uart_port *port)
78{
79 struct tty_struct *tty = port->state->port.tty;
80 unsigned int status, ch, rsr, flag;
81 unsigned int max_chars = port->fifosize;
82
83 status = UART_GET_STATUS(port);
84
85 while (UART_RX_DATA(status) && (max_chars--)) {
86
87 ch = UART_GET_CHAR(port);
88 flag = TTY_NORMAL;
89
90 port->icount.rx++;
91
92 rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX;
93 UART_PUT_STATUS(port, 0);
94 if (rsr & UART_STATUS_ERR) {
95
96 if (rsr & UART_STATUS_BR) {
97 rsr &= ~(UART_STATUS_FE | UART_STATUS_PE);
98 port->icount.brk++;
99 if (uart_handle_break(port))
100 goto ignore_char;
101 } else if (rsr & UART_STATUS_PE) {
102 port->icount.parity++;
103 } else if (rsr & UART_STATUS_FE) {
104 port->icount.frame++;
105 }
106 if (rsr & UART_STATUS_OE)
107 port->icount.overrun++;
108
109 rsr &= port->read_status_mask;
110
111 if (rsr & UART_STATUS_PE)
112 flag = TTY_PARITY;
113 else if (rsr & UART_STATUS_FE)
114 flag = TTY_FRAME;
115 }
116
117 if (uart_handle_sysrq_char(port, ch))
118 goto ignore_char;
119
120 uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag);
121
122
123 ignore_char:
124 status = UART_GET_STATUS(port);
125 }
126
127 tty_flip_buffer_push(tty);
128}
129
130static void apbuart_tx_chars(struct uart_port *port)
131{
132 struct circ_buf *xmit = &port->state->xmit;
133 int count;
134
135 if (port->x_char) {
136 UART_PUT_CHAR(port, port->x_char);
137 port->icount.tx++;
138 port->x_char = 0;
139 return;
140 }
141
142 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
143 apbuart_stop_tx(port);
144 return;
145 }
146
147 /* amba: fill FIFO */
148 count = port->fifosize >> 1;
149 do {
150 UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
151 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
152 port->icount.tx++;
153 if (uart_circ_empty(xmit))
154 break;
155 } while (--count > 0);
156
157 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
158 uart_write_wakeup(port);
159
160 if (uart_circ_empty(xmit))
161 apbuart_stop_tx(port);
162}
163
164static irqreturn_t apbuart_int(int irq, void *dev_id)
165{
166 struct uart_port *port = dev_id;
167 unsigned int status;
168
169 spin_lock(&port->lock);
170
171 status = UART_GET_STATUS(port);
172 if (status & UART_STATUS_DR)
173 apbuart_rx_chars(port);
174 if (status & UART_STATUS_THE)
175 apbuart_tx_chars(port);
176
177 spin_unlock(&port->lock);
178
179 return IRQ_HANDLED;
180}
181
182static unsigned int apbuart_tx_empty(struct uart_port *port)
183{
184 unsigned int status = UART_GET_STATUS(port);
185 return status & UART_STATUS_THE ? TIOCSER_TEMT : 0;
186}
187
188static unsigned int apbuart_get_mctrl(struct uart_port *port)
189{
190 /* The GRLIB APBUART handles flow control in hardware */
191 return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
192}
193
194static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
195{
196 /* The GRLIB APBUART handles flow control in hardware */
197}
198
199static void apbuart_break_ctl(struct uart_port *port, int break_state)
200{
201 /* We don't support sending break */
202}
203
204static int apbuart_startup(struct uart_port *port)
205{
206 int retval;
207 unsigned int cr;
208
209 /* Allocate the IRQ */
210 retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port);
211 if (retval)
212 return retval;
213
214 /* Finally, enable interrupts */
215 cr = UART_GET_CTRL(port);
216 UART_PUT_CTRL(port,
217 cr | UART_CTRL_RE | UART_CTRL_TE |
218 UART_CTRL_RI | UART_CTRL_TI);
219
220 return 0;
221}
222
223static void apbuart_shutdown(struct uart_port *port)
224{
225 unsigned int cr;
226
227 /* disable all interrupts, disable the port */
228 cr = UART_GET_CTRL(port);
229 UART_PUT_CTRL(port,
230 cr & ~(UART_CTRL_RE | UART_CTRL_TE |
231 UART_CTRL_RI | UART_CTRL_TI));
232
233 /* Free the interrupt */
234 free_irq(port->irq, port);
235}
236
237static void apbuart_set_termios(struct uart_port *port,
238 struct ktermios *termios, struct ktermios *old)
239{
240 unsigned int cr;
241 unsigned long flags;
242 unsigned int baud, quot;
243
244 /* Ask the core to calculate the divisor for us. */
245 baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
246 if (baud == 0)
247 panic("invalid baudrate %i\n", port->uartclk / 16);
248
249 /* uart_get_divisor calc a *16 uart freq, apbuart is *8 */
250 quot = (uart_get_divisor(port, baud)) * 2;
251 cr = UART_GET_CTRL(port);
252 cr &= ~(UART_CTRL_PE | UART_CTRL_PS);
253
254 if (termios->c_cflag & PARENB) {
255 cr |= UART_CTRL_PE;
256 if ((termios->c_cflag & PARODD))
257 cr |= UART_CTRL_PS;
258 }
259
260 /* Enable flow control. */
261 if (termios->c_cflag & CRTSCTS)
262 cr |= UART_CTRL_FL;
263
264 spin_lock_irqsave(&port->lock, flags);
265
266 /* Update the per-port timeout. */
267 uart_update_timeout(port, termios->c_cflag, baud);
268
269 port->read_status_mask = UART_STATUS_OE;
270 if (termios->c_iflag & INPCK)
271 port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
272
273 /* Characters to ignore */
274 port->ignore_status_mask = 0;
275 if (termios->c_iflag & IGNPAR)
276 port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
277
278 /* Ignore all characters if CREAD is not set. */
279 if ((termios->c_cflag & CREAD) == 0)
280 port->ignore_status_mask |= UART_DUMMY_RSR_RX;
281
282 /* Set baud rate */
283 quot -= 1;
284 UART_PUT_SCAL(port, quot);
285 UART_PUT_CTRL(port, cr);
286
287 spin_unlock_irqrestore(&port->lock, flags);
288}
289
290static const char *apbuart_type(struct uart_port *port)
291{
292 return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL;
293}
294
295static void apbuart_release_port(struct uart_port *port)
296{
297 release_mem_region(port->mapbase, 0x100);
298}
299
300static int apbuart_request_port(struct uart_port *port)
301{
302 return request_mem_region(port->mapbase, 0x100, "grlib-apbuart")
303 != NULL ? 0 : -EBUSY;
304 return 0;
305}
306
307/* Configure/autoconfigure the port */
308static void apbuart_config_port(struct uart_port *port, int flags)
309{
310 if (flags & UART_CONFIG_TYPE) {
311 port->type = PORT_APBUART;
312 apbuart_request_port(port);
313 }
314}
315
316/* Verify the new serial_struct (for TIOCSSERIAL) */
317static int apbuart_verify_port(struct uart_port *port,
318 struct serial_struct *ser)
319{
320 int ret = 0;
321 if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART)
322 ret = -EINVAL;
323 if (ser->irq < 0 || ser->irq >= NR_IRQS)
324 ret = -EINVAL;
325 if (ser->baud_base < 9600)
326 ret = -EINVAL;
327 return ret;
328}
329
330static struct uart_ops grlib_apbuart_ops = {
331 .tx_empty = apbuart_tx_empty,
332 .set_mctrl = apbuart_set_mctrl,
333 .get_mctrl = apbuart_get_mctrl,
334 .stop_tx = apbuart_stop_tx,
335 .start_tx = apbuart_start_tx,
336 .stop_rx = apbuart_stop_rx,
337 .enable_ms = apbuart_enable_ms,
338 .break_ctl = apbuart_break_ctl,
339 .startup = apbuart_startup,
340 .shutdown = apbuart_shutdown,
341 .set_termios = apbuart_set_termios,
342 .type = apbuart_type,
343 .release_port = apbuart_release_port,
344 .request_port = apbuart_request_port,
345 .config_port = apbuart_config_port,
346 .verify_port = apbuart_verify_port,
347};
348
349static struct uart_port grlib_apbuart_ports[UART_NR];
350static struct device_node *grlib_apbuart_nodes[UART_NR];
351
352static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber)
353{
354 int ctrl, loop = 0;
355 int status;
356 int fifosize;
357 unsigned long flags;
358
359 ctrl = UART_GET_CTRL(port);
360
361 /*
362 * Enable the transceiver and wait for it to be ready to send data.
363 * Clear interrupts so that this process will not be externally
364 * interrupted in the middle (which can cause the transceiver to
365 * drain prematurely).
366 */
367
368 local_irq_save(flags);
369
370 UART_PUT_CTRL(port, ctrl | UART_CTRL_TE);
371
372 while (!UART_TX_READY(UART_GET_STATUS(port)))
373 loop++;
374
375 /*
376 * Disable the transceiver so data isn't actually sent during the
377 * actual test.
378 */
379
380 UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE));
381
382 fifosize = 1;
383 UART_PUT_CHAR(port, 0);
384
385 /*
386 * So long as transmitting a character increments the tranceivier FIFO
387 * length the FIFO must be at least that big. These bytes will
388 * automatically drain off of the FIFO.
389 */
390
391 status = UART_GET_STATUS(port);
392 while (((status >> 20) & 0x3F) == fifosize) {
393 fifosize++;
394 UART_PUT_CHAR(port, 0);
395 status = UART_GET_STATUS(port);
396 }
397
398 fifosize--;
399
400 UART_PUT_CTRL(port, ctrl);
401 local_irq_restore(flags);
402
403 if (fifosize == 0)
404 fifosize = 1;
405
406 return fifosize;
407}
408
409static void apbuart_flush_fifo(struct uart_port *port)
410{
411 int i;
412
413 for (i = 0; i < port->fifosize; i++)
414 UART_GET_CHAR(port);
415}
416
417
418/* ======================================================================== */
419/* Console driver, if enabled */
420/* ======================================================================== */
421
422#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
423
424static void apbuart_console_putchar(struct uart_port *port, int ch)
425{
426 unsigned int status;
427 do {
428 status = UART_GET_STATUS(port);
429 } while (!UART_TX_READY(status));
430 UART_PUT_CHAR(port, ch);
431}
432
433static void
434apbuart_console_write(struct console *co, const char *s, unsigned int count)
435{
436 struct uart_port *port = &grlib_apbuart_ports[co->index];
437 unsigned int status, old_cr, new_cr;
438
439 /* First save the CR then disable the interrupts */
440 old_cr = UART_GET_CTRL(port);
441 new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI);
442 UART_PUT_CTRL(port, new_cr);
443
444 uart_console_write(port, s, count, apbuart_console_putchar);
445
446 /*
447 * Finally, wait for transmitter to become empty
448 * and restore the TCR
449 */
450 do {
451 status = UART_GET_STATUS(port);
452 } while (!UART_TX_READY(status));
453 UART_PUT_CTRL(port, old_cr);
454}
455
456static void __init
457apbuart_console_get_options(struct uart_port *port, int *baud,
458 int *parity, int *bits)
459{
460 if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) {
461
462 unsigned int quot, status;
463 status = UART_GET_STATUS(port);
464
465 *parity = 'n';
466 if (status & UART_CTRL_PE) {
467 if ((status & UART_CTRL_PS) == 0)
468 *parity = 'e';
469 else
470 *parity = 'o';
471 }
472
473 *bits = 8;
474 quot = UART_GET_SCAL(port) / 8;
475 *baud = port->uartclk / (16 * (quot + 1));
476 }
477}
478
479static int __init apbuart_console_setup(struct console *co, char *options)
480{
481 struct uart_port *port;
482 int baud = 38400;
483 int bits = 8;
484 int parity = 'n';
485 int flow = 'n';
486
487 pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n",
488 co, co->index, options);
489
490 /*
491 * Check whether an invalid uart number has been specified, and
492 * if so, search for the first available port that does have
493 * console support.
494 */
495 if (co->index >= grlib_apbuart_port_nr)
496 co->index = 0;
497
498 port = &grlib_apbuart_ports[co->index];
499
500 spin_lock_init(&port->lock);
501
502 if (options)
503 uart_parse_options(options, &baud, &parity, &bits, &flow);
504 else
505 apbuart_console_get_options(port, &baud, &parity, &bits);
506
507 return uart_set_options(port, co, baud, parity, bits, flow);
508}
509
510static struct uart_driver grlib_apbuart_driver;
511
512static struct console grlib_apbuart_console = {
513 .name = "ttyS",
514 .write = apbuart_console_write,
515 .device = uart_console_device,
516 .setup = apbuart_console_setup,
517 .flags = CON_PRINTBUFFER,
518 .index = -1,
519 .data = &grlib_apbuart_driver,
520};
521
522
523static void grlib_apbuart_configure(void);
524
525static int __init apbuart_console_init(void)
526{
527 grlib_apbuart_configure();
528 register_console(&grlib_apbuart_console);
529 return 0;
530}
531
532console_initcall(apbuart_console_init);
533
534#define APBUART_CONSOLE (&grlib_apbuart_console)
535#else
536#define APBUART_CONSOLE NULL
537#endif
538
539static struct uart_driver grlib_apbuart_driver = {
540 .owner = THIS_MODULE,
541 .driver_name = "serial",
542 .dev_name = "ttyS",
543 .major = SERIAL_APBUART_MAJOR,
544 .minor = SERIAL_APBUART_MINOR,
545 .nr = UART_NR,
546 .cons = APBUART_CONSOLE,
547};
548
549
550/* ======================================================================== */
551/* OF Platform Driver */
552/* ======================================================================== */
553
554static int __devinit apbuart_probe(struct of_device *op,
555 const struct of_device_id *match)
556{
557 int i = -1;
558 struct uart_port *port = NULL;
559
560 i = 0;
561 for (i = 0; i < grlib_apbuart_port_nr; i++) {
562 if (op->node == grlib_apbuart_nodes[i])
563 break;
564 }
565
566 port = &grlib_apbuart_ports[i];
567 port->dev = &op->dev;
568
569 uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port);
570
571 apbuart_flush_fifo((struct uart_port *) port);
572
573 printk(KERN_INFO "grlib-apbuart at 0x%x, irq %d\n",
574 port->mapbase, port->irq);
575 return 0;
576
577}
578
579static struct of_device_id __initdata apbuart_match[] = {
580 {
581 .name = "GAISLER_APBUART",
582 },
583 {},
584};
585
586static struct of_platform_driver grlib_apbuart_of_driver = {
587 .match_table = apbuart_match,
588 .probe = apbuart_probe,
589 .driver = {
590 .owner = THIS_MODULE,
591 .name = "grlib-apbuart",
592 },
593};
594
595
596static void grlib_apbuart_configure(void)
597{
598 static int enum_done;
599 struct device_node *np;
600 struct uart_port *port = NULL;
601
602 int node;
603 int freq_khz;
604 int v = 0, d = 0;
605 unsigned int addr;
606 int irq, line;
607 struct amba_prom_registers *regs;
608
609 if (enum_done)
610 return;
611
612 /* Get bus frequency */
613 node = prom_getchild(prom_root_node);
614 freq_khz = prom_getint(node, "clock-frequency");
615
616 line = 0;
617 for_each_matching_node(np, apbuart_match) {
618
619 int *vendor = (int *) of_get_property(np, "vendor", NULL);
620 int *device = (int *) of_get_property(np, "device", NULL);
621 int *irqs = (int *) of_get_property(np, "interrupts", NULL);
622 regs = (struct amba_prom_registers *)
623 of_get_property(np, "reg", NULL);
624
625 if (vendor)
626 v = *vendor;
627 if (device)
628 d = *device;
629
630 if (!irqs || !regs)
631 return;
632
633 grlib_apbuart_nodes[line] = np;
634
635 addr = regs->phys_addr;
636 irq = *irqs;
637
638 port = &grlib_apbuart_ports[line];
639
640 port->mapbase = addr;
641 port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));
642 port->irq = irq;
643 port->iotype = UPIO_MEM;
644 port->ops = &grlib_apbuart_ops;
645 port->flags = UPF_BOOT_AUTOCONF;
646 port->line = line;
647 port->uartclk = freq_khz * 1000;
648 port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line);
649 line++;
650
651 /* We support maximum UART_NR uarts ... */
652 if (line == UART_NR)
653 break;
654
655 }
656
657 enum_done = 1;
658
659 grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;
660}
661
662static int __init grlib_apbuart_init(void)
663{
664 int ret;
665
666 /* Find all APBUARTS in device the tree and initialize their ports */
667 grlib_apbuart_configure();
668
669 printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
670
671 ret = uart_register_driver(&grlib_apbuart_driver);
672
673 if (ret) {
674 printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
675 __FILE__, ret);
676 return ret;
677 }
678
679 ret = of_register_driver(&grlib_apbuart_of_driver, &of_platform_bus_type);
680
681 if (ret) {
682 printk(KERN_ERR
683 "%s: of_register_platform_driver failed (%i)\n",
684 __FILE__, ret);
685 uart_unregister_driver(&grlib_apbuart_driver);
686 return ret;
687 }
688
689 return ret;
690}
691
692static void __exit grlib_apbuart_exit(void)
693{
694 int i;
695
696 for (i = 0; i < grlib_apbuart_port_nr; i++)
697 uart_remove_one_port(&grlib_apbuart_driver,
698 &grlib_apbuart_ports[i]);
699
700 uart_unregister_driver(&grlib_apbuart_driver);
701
702}
703
704module_init(grlib_apbuart_init);
705module_exit(grlib_apbuart_exit);
706
707MODULE_AUTHOR("Aeroflex Gaisler AB");
708MODULE_DESCRIPTION("GRLIB APBUART serial driver");
709MODULE_VERSION("2.1");
710MODULE_LICENSE("GPL");