1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <linux/config.h>
25#include <linux/types.h>
26#include <linux/serial.h>
27#include <linux/module.h>
28#include <linux/console.h>
29#include <linux/kdev_t.h>
30#include <linux/major.h>
31#include <linux/termios.h>
32#include <linux/spinlock.h>
33#include <linux/irq.h>
34#include <linux/errno.h>
35#include <linux/tty.h>
36#include <linux/sched.h>
37#include <linux/tty_flip.h>
38#include <linux/timer.h>
39#include <linux/init.h>
40#include <linux/mm.h>
41#include <asm/delay.h>
42#include <asm/io.h>
43#include <asm/uaccess.h>
44#include <asm/sibyte/swarm.h>
45#include <asm/sibyte/sb1250_regs.h>
46#include <asm/sibyte/sb1250_uart.h>
47#include <asm/sibyte/sb1250_int.h>
48#include <asm/sibyte/sb1250.h>
49#include <asm/sibyte/64bit.h>
50#include <asm/war.h>
51
52
53#undef DUART_SPEW
54
55#define DEFAULT_CFLAGS (CS8 | B115200)
56
57#define TX_INTEN 1
58#define DUART_INITIALIZED 2
59
60#ifndef MIN
61#define MIN(a,b) ((a) < (b) ? (a) : (b))
62#endif
63
64#define DUART_MAX_LINE 2
65char sb1250_duart_present[DUART_MAX_LINE] = {1,1};
66
67
68
69
70
71static struct tty_driver sb1250_duart_driver, sb1250_duart_callout_driver;
72static int duart_refcount;
73static struct tty_struct *duart_table[DUART_MAX_LINE];
74static struct termios *duart_termios[DUART_MAX_LINE];
75static struct termios *duart_termios_locked[DUART_MAX_LINE];
76
77
78
79
80
81static spinlock_t open_lock = SPIN_LOCK_UNLOCKED;
82
83typedef struct {
84 unsigned char outp_buf[SERIAL_XMIT_SIZE];
85 unsigned int outp_head;
86 unsigned int outp_tail;
87 unsigned int outp_count;
88 spinlock_t outp_lock;
89 unsigned int open;
90 unsigned int line;
91 unsigned int last_cflags;
92 unsigned long flags;
93 struct tty_struct *tty;
94
95 u32 *status;
96 u32 *imr;
97 u32 *tx_hold;
98 u32 *rx_hold;
99 u32 *mode_1;
100 u32 *mode_2;
101 u32 *clk_sel;
102 u32 *cmd;
103} uart_state_t;
104
105static uart_state_t uart_states[DUART_MAX_LINE];
106
107
108
109
110
111
112
113
114
115
116#if SIBYTE_1956_WAR
117static unsigned int last_mode1[DUART_MAX_LINE];
118#endif
119
120static inline u32 READ_SERCSR(u32 *addr, int line)
121{
122 u32 val = csr_in32(addr);
123#if SIBYTE_1956_WAR
124 csr_out32(last_mode1[line], uart_states[line].mode_1);
125#endif
126 return val;
127}
128
129static inline void WRITE_SERCSR(u32 val, u32 *addr, int line)
130{
131 csr_out32(val, addr);
132#if SIBYTE_1956_WAR
133 csr_out32(last_mode1[line], uart_states[line].mode_1);
134#endif
135}
136
137static void init_duart_port(uart_state_t *port, int line)
138{
139 if (!(port->flags & DUART_INITIALIZED)) {
140 port->line = line;
141 port->status = (u32 *)(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_STATUS));
142 port->imr = (u32 *)(IO_SPACE_BASE | A_DUART_IMRREG(line));
143 port->tx_hold = (u32 *)(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_TX_HOLD));
144 port->rx_hold = (u32 *)(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_RX_HOLD));
145 port->mode_1 = (u32 *)(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_MODE_REG_1));
146 port->mode_2 = (u32 *)(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_MODE_REG_2));
147 port->clk_sel = (u32 *)(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_CLK_SEL));
148 port->cmd = (u32 *)(IO_SPACE_BASE | A_DUART_CHANREG(line, R_DUART_CMD));
149 port->flags |= DUART_INITIALIZED;
150 }
151}
152
153
154
155
156
157static inline void duart_mask_ints(unsigned int line, unsigned int mask)
158{
159 uart_state_t *port = uart_states + line;
160 u64 tmp = READ_SERCSR(port->imr, line);
161 WRITE_SERCSR(tmp & ~mask, port->imr, line);
162}
163
164
165
166static inline void duart_unmask_ints(unsigned int line, unsigned int mask)
167{
168 uart_state_t *port = uart_states + line;
169 u64 tmp = READ_SERCSR(port->imr, line);
170 WRITE_SERCSR(tmp | mask, port->imr, line);
171}
172
173static inline void transmit_char_pio(uart_state_t *us)
174{
175 struct tty_struct *tty = us->tty;
176 int blocked = 0;
177
178 if (spin_trylock(&us->outp_lock)) {
179 for (;;) {
180 if (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_RDY))
181 break;
182 if (us->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
183 break;
184 } else {
185 WRITE_SERCSR(us->outp_buf[us->outp_head],
186 us->tx_hold, us->line);
187 us->outp_head = (us->outp_head + 1) & (SERIAL_XMIT_SIZE-1);
188 if (--us->outp_count <= 0)
189 break;
190 }
191 udelay(10);
192 }
193 spin_unlock(&us->outp_lock);
194 } else {
195 blocked = 1;
196 }
197
198 if (!us->outp_count || tty->stopped ||
199 tty->hw_stopped || blocked) {
200 us->flags &= ~TX_INTEN;
201 duart_mask_ints(us->line, M_DUART_IMR_TX);
202 }
203
204 if (us->open &&
205 (us->outp_count < (SERIAL_XMIT_SIZE/2))) {
206
207
208
209
210
211 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
212 tty->ldisc.write_wakeup)
213 tty->ldisc.write_wakeup(tty);
214 wake_up_interruptible(&tty->write_wait);
215 }
216}
217
218
219
220
221
222
223
224static void duart_int(int irq, void *dev_id, struct pt_regs *regs)
225{
226 uart_state_t *us = (uart_state_t *)dev_id;
227 struct tty_struct *tty = us->tty;
228 unsigned int status = READ_SERCSR(us->status, us->line);
229
230#ifdef DUART_SPEW
231 printk("DUART INT\n");
232#endif
233
234 if (status & M_DUART_RX_RDY) {
235 int counter = 2048;
236 unsigned int ch;
237
238 if (status & M_DUART_OVRUN_ERR)
239 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
240 if (status & M_DUART_PARITY_ERR) {
241 printk("Parity error!\n");
242 } else if (status & M_DUART_FRM_ERR) {
243 printk("Frame error!\n");
244 }
245
246 while (counter > 0) {
247 if (!(READ_SERCSR(us->status, us->line) & M_DUART_RX_RDY))
248 break;
249 ch = READ_SERCSR(us->rx_hold, us->line);
250 if (tty->flip.count < TTY_FLIPBUF_SIZE) {
251 *tty->flip.char_buf_ptr++ = ch;
252 *tty->flip.flag_buf_ptr++ = 0;
253 tty->flip.count++;
254 }
255 udelay(1);
256 counter--;
257 }
258 tty_flip_buffer_push(tty);
259 }
260
261 if (status & M_DUART_TX_RDY) {
262 transmit_char_pio(us);
263 }
264}
265
266
267
268
269
270
271static int duart_write_room(struct tty_struct *tty)
272{
273 uart_state_t *us = (uart_state_t *) tty->driver_data;
274 int retval;
275
276 retval = SERIAL_XMIT_SIZE - us->outp_count;
277
278#ifdef DUART_SPEW
279 printk("duart_write_room called, returning %i\n", retval);
280#endif
281
282 return retval;
283}
284
285
286
287static inline int copy_buf(char *dest, const char *src, int size, int from_user)
288{
289 if (from_user) {
290 (void) copy_from_user(dest, src, size);
291 } else {
292 memcpy(dest, src, size);
293 }
294 return size;
295}
296
297
298
299
300
301static int duart_write(struct tty_struct * tty, int from_user,
302 const unsigned char *buf, int count)
303{
304 uart_state_t *us;
305 int c, t, total = 0;
306 unsigned long flags;
307
308 if (!tty) return 0;
309
310 us = tty->driver_data;
311 if (!us) return 0;
312
313#ifdef DUART_SPEW
314 printk("duart_write called for %i chars by %i (%s)\n", count, current->pid, current->comm);
315#endif
316
317 spin_lock_irqsave(&us->outp_lock, flags);
318
319 for (;;) {
320 c = count;
321
322 t = SERIAL_XMIT_SIZE - us->outp_tail;
323 if (t < c) c = t;
324
325 t = SERIAL_XMIT_SIZE - 1 - us->outp_count;
326 if (t < c) c = t;
327
328 if (c <= 0) break;
329
330 if (from_user) {
331 if (copy_from_user(us->outp_buf + us->outp_tail, buf, c)) {
332 spin_unlock_irqrestore(&us->outp_lock, flags);
333 return -EFAULT;
334 }
335 } else {
336 memcpy(us->outp_buf + us->outp_tail, buf, c);
337 }
338
339 us->outp_count += c;
340 us->outp_tail = (us->outp_tail + c) & (SERIAL_XMIT_SIZE - 1);
341 buf += c;
342 count -= c;
343 total += c;
344 }
345
346 spin_unlock_irqrestore(&us->outp_lock, flags);
347
348 if (us->outp_count && !tty->stopped &&
349 !tty->hw_stopped && !(us->flags & TX_INTEN)) {
350 us->flags |= TX_INTEN;
351 duart_unmask_ints(us->line, M_DUART_IMR_TX);
352 }
353
354 return total;
355}
356
357
358
359
360static void duart_put_char(struct tty_struct *tty, u_char ch)
361{
362 uart_state_t *us = (uart_state_t *) tty->driver_data;
363 unsigned long flags;
364
365#ifdef DUART_SPEW
366 printk("duart_put_char called. Char is %x (%c)\n", (int)ch, ch);
367#endif
368
369 spin_lock_irqsave(&us->outp_lock, flags);
370
371 if (us->outp_count == SERIAL_XMIT_SIZE) {
372 spin_unlock_irqrestore(&us->outp_lock, flags);
373 return;
374 }
375
376 us->outp_buf[us->outp_tail] = ch;
377 us->outp_tail = (us->outp_tail + 1) &(SERIAL_XMIT_SIZE-1);
378 us->outp_count++;
379
380 spin_unlock_irqrestore(&us->outp_lock, flags);
381}
382
383static void duart_flush_chars(struct tty_struct * tty)
384{
385 uart_state_t *port;
386
387 if (!tty) return;
388
389 port = tty->driver_data;
390
391 if (!port) return;
392
393 if (port->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
394 return;
395 }
396
397 port->flags |= TX_INTEN;
398 duart_unmask_ints(port->line, M_DUART_IMR_TX);
399}
400
401
402
403static int duart_chars_in_buffer(struct tty_struct *tty)
404{
405 uart_state_t *us = (uart_state_t *) tty->driver_data;
406 int retval;
407
408 retval = us->outp_count;
409
410#ifdef DUART_SPEW
411 printk("duart_chars_in_buffer returning %i\n", retval);
412#endif
413 return retval;
414}
415
416
417
418static void duart_flush_buffer(struct tty_struct *tty)
419{
420 uart_state_t *us = (uart_state_t *) tty->driver_data;
421 unsigned long flags;
422
423#ifdef DUART_SPEW
424 printk("duart_flush_buffer called\n");
425#endif
426 spin_lock_irqsave(&us->outp_lock, flags);
427 us->outp_head = us->outp_tail = us->outp_count = 0;
428 spin_unlock_irqrestore(&us->outp_lock, flags);
429
430 wake_up_interruptible(&us->tty->write_wait);
431 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
432 tty->ldisc.write_wakeup)
433 tty->ldisc.write_wakeup(tty);
434}
435
436
437
438static inline void duart_set_cflag(unsigned int line, unsigned int cflag)
439{
440 unsigned int mode_reg1 = 0, mode_reg2 = 0;
441 unsigned int clk_divisor;
442 uart_state_t *port = uart_states + line;
443
444 switch (cflag & CSIZE) {
445 case CS7:
446 mode_reg1 |= V_DUART_BITS_PER_CHAR_7;
447
448 default:
449
450
451 mode_reg1 |= 0x0;
452 break;
453 }
454 if (cflag & CSTOPB) {
455 mode_reg2 |= M_DUART_STOP_BIT_LEN_2;
456 }
457 if (!(cflag & PARENB)) {
458 mode_reg1 |= V_DUART_PARITY_MODE_NONE;
459 }
460 if (cflag & PARODD) {
461 mode_reg1 |= M_DUART_PARITY_TYPE_ODD;
462 }
463
464
465
466
467 switch (cflag & CBAUD) {
468 case B200:
469 case B300:
470 case B1200: clk_divisor = 4095; break;
471 case B1800: clk_divisor = 2776; break;
472 case B2400: clk_divisor = 2082; break;
473 case B4800: clk_divisor = 1040; break;
474 default:
475 case B9600: clk_divisor = 519; break;
476 case B19200: clk_divisor = 259; break;
477 case B38400: clk_divisor = 129; break;
478 case B57600: clk_divisor = 85; break;
479 case B115200: clk_divisor = 42; break;
480 }
481 WRITE_SERCSR(mode_reg1, port->mode_1, port->line);
482 WRITE_SERCSR(mode_reg2, port->mode_2, port->line);
483 WRITE_SERCSR(clk_divisor, port->clk_sel, port->line);
484 port->last_cflags = cflag;
485}
486
487
488
489static void duart_set_termios(struct tty_struct *tty, struct termios *old)
490{
491 uart_state_t *us = (uart_state_t *) tty->driver_data;
492
493#ifdef DUART_SPEW
494 printk("duart_set_termios called by %i (%s)\n", current->pid, current->comm);
495#endif
496 if (old && tty->termios->c_cflag == old->c_cflag)
497 return;
498 duart_set_cflag(us->line, tty->termios->c_cflag);
499}
500
501static int duart_ioctl(struct tty_struct *tty, struct file * file,
502 unsigned int cmd, unsigned long arg)
503{
504
505
506 switch (cmd) {
507 case TIOCMGET:
508 printk("Ignoring TIOCMGET\n");
509 break;
510 case TIOCMBIS:
511 printk("Ignoring TIOCMBIS\n");
512 break;
513 case TIOCMBIC:
514 printk("Ignoring TIOCMBIC\n");
515 break;
516 case TIOCMSET:
517 printk("Ignoring TIOCMSET\n");
518 break;
519 case TIOCGSERIAL:
520 printk("Ignoring TIOCGSERIAL\n");
521 break;
522 case TIOCSSERIAL:
523 printk("Ignoring TIOCSSERIAL\n");
524 break;
525 case TIOCSERCONFIG:
526 printk("Ignoring TIOCSERCONFIG\n");
527 break;
528 case TIOCSERGETLSR:
529 printk("Ignoring TIOCSERGETLSR\n");
530 break;
531 case TIOCSERGSTRUCT:
532 printk("Ignoring TIOCSERGSTRUCT\n");
533 break;
534 case TIOCMIWAIT:
535 printk("Ignoring TIOCMIWAIT\n");
536 break;
537 case TIOCGICOUNT:
538 printk("Ignoring TIOCGICOUNT\n");
539 break;
540 case TIOCSERGWILD:
541 printk("Ignoring TIOCSERGWILD\n");
542 break;
543 case TIOCSERSWILD:
544 printk("Ignoring TIOCSERSWILD\n");
545 break;
546 default:
547 break;
548 }
549
550 return -ENOIOCTLCMD;
551#if 0
552 if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
553 (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
554 (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
555 if (tty->flags & (1 << TTY_IO_ERROR))
556 return -EIO;
557 }
558
559 switch (cmd) {
560 case TIOCMGET:
561 case TIOCMBIS:
562 case TIOCMBIC:
563 case TIOCMSET:
564 case TIOCGSERIAL:
565 case TIOCSSERIAL:
566 case TIOCSERCONFIG:
567 case TIOCSERGETLSR:
568 case TIOCSERGSTRUCT:
569 case TIOCMIWAIT:
570 case TIOCGICOUNT:
571 case TIOCSERGWILD:
572 case TIOCSERSWILD:
573
574 printk("IOCTL needs implementing: %x\n", cmd);
575
576 default:
577 printk("Unknown ioctl: %x\n", cmd);
578 }
579#endif
580 return 0;
581}
582
583
584static void duart_start(struct tty_struct *tty)
585{
586 uart_state_t *us = (uart_state_t *) tty->driver_data;
587
588#ifdef DUART_SPEW
589 printk("duart_start called\n");
590#endif
591
592 if (us->outp_count && !(us->flags & TX_INTEN)) {
593 us->flags |= TX_INTEN;
594 duart_unmask_ints(us->line, M_DUART_IMR_TX);
595 }
596}
597
598
599static void duart_stop(struct tty_struct *tty)
600{
601 uart_state_t *us = (uart_state_t *) tty->driver_data;
602
603#ifdef DUART_SPEW
604 printk("duart_stop called\n");
605#endif
606
607 if (us->outp_count && (us->flags & TX_INTEN)) {
608 us->flags &= ~TX_INTEN;
609 duart_mask_ints(us->line, M_DUART_IMR_TX);
610 }
611}
612
613
614
615
616
617
618
619static void duart_wait_until_sent(struct tty_struct *tty, int timeout)
620{
621 uart_state_t *us = (uart_state_t *) tty->driver_data;
622 unsigned long orig_jiffies;
623
624 orig_jiffies = jiffies;
625#ifdef DUART_SPEW
626 printk("duart_wait_until_sent(%d)+\n", timeout);
627#endif
628 while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT)) {
629 set_current_state(TASK_INTERRUPTIBLE);
630 schedule_timeout(1);
631 if (signal_pending(current))
632 break;
633 if (timeout && time_after(jiffies, orig_jiffies + timeout))
634 break;
635 }
636#ifdef DUART_SPEW
637 printk("duart_wait_until_sent()-\n");
638#endif
639}
640
641
642
643
644static void duart_hangup(struct tty_struct *tty)
645{
646 uart_state_t *us = (uart_state_t *) tty->driver_data;
647
648 duart_flush_buffer(tty);
649 us->open = 0;
650 us->tty = 0;
651}
652
653
654
655
656
657
658static int duart_open(struct tty_struct *tty, struct file *filp)
659{
660 uart_state_t *us;
661 unsigned int line = MINOR(tty->device) - tty->driver.minor_start;
662 unsigned long flags;
663
664 MOD_INC_USE_COUNT;
665
666 if ((line < 0) || (line >= DUART_MAX_LINE) || !sb1250_duart_present[line]) {
667 MOD_DEC_USE_COUNT;
668 return -ENODEV;
669 }
670
671#ifdef DUART_SPEW
672 printk("duart_open called by %i (%s), tty is %p, rw is %p, ww is %p\n",
673 current->pid, current->comm, tty, tty->read_wait,
674 tty->write_wait);
675#endif
676
677 us = uart_states + line;
678 tty->driver_data = us;
679
680 spin_lock_irqsave(&open_lock, flags);
681 if (!us->open) {
682 us->tty = tty;
683 us->tty->termios->c_cflag = us->last_cflags;
684 }
685 us->open++;
686 us->flags &= ~TX_INTEN;
687 duart_unmask_ints(line, M_DUART_IMR_RX);
688 spin_unlock_irqrestore(&open_lock, flags);
689
690 return 0;
691}
692
693
694
695
696
697
698
699static void duart_close(struct tty_struct *tty, struct file *filp)
700{
701 uart_state_t *us = (uart_state_t *) tty->driver_data;
702 unsigned long flags;
703
704#ifdef DUART_SPEW
705 printk("duart_close called by %i (%s)\n", current->pid, current->comm);
706#endif
707
708 if (!us || !us->open)
709 return;
710
711 spin_lock_irqsave(&open_lock, flags);
712 if (tty_hung_up_p(filp)) {
713 MOD_DEC_USE_COUNT;
714 spin_unlock_irqrestore(&open_lock, flags);
715 return;
716 }
717
718 if (--us->open < 0) {
719 us->open = 0;
720 printk(KERN_ERR "duart: bad open count: %d\n", us->open);
721 }
722 if (us->open) {
723 spin_unlock_irqrestore(&open_lock, flags);
724 return;
725 }
726
727 spin_unlock_irqrestore(&open_lock, flags);
728
729 tty->closing = 1;
730
731
732 duart_mask_ints(us->line, M_DUART_IMR_RX);
733
734 while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT))
735 ;
736
737 if (tty->driver.flush_buffer)
738 tty->driver.flush_buffer(tty);
739 if (tty->ldisc.flush_buffer)
740 tty->ldisc.flush_buffer(tty);
741 tty->closing = 0;
742
743 MOD_DEC_USE_COUNT;
744}
745
746
747
748
749static int __init sb1250_duart_init(void)
750{
751 int i;
752
753 sb1250_duart_driver.magic = TTY_DRIVER_MAGIC;
754 sb1250_duart_driver.driver_name = "serial";
755#ifdef CONFIG_DEVFS_FS
756 sb1250_duart_driver.name = "tts/%d";
757#else
758 sb1250_duart_driver.name = "ttyS";
759#endif
760 sb1250_duart_driver.major = TTY_MAJOR;
761 sb1250_duart_driver.minor_start = SB1250_DUART_MINOR_BASE;
762 sb1250_duart_driver.num = DUART_MAX_LINE;
763 sb1250_duart_driver.type = TTY_DRIVER_TYPE_SERIAL;
764 sb1250_duart_driver.subtype = SERIAL_TYPE_NORMAL;
765 sb1250_duart_driver.init_termios = tty_std_termios;
766 sb1250_duart_driver.flags = TTY_DRIVER_REAL_RAW;
767 sb1250_duart_driver.refcount = &duart_refcount;
768 sb1250_duart_driver.table = duart_table;
769 sb1250_duart_driver.termios = duart_termios;
770 sb1250_duart_driver.termios_locked = duart_termios_locked;
771
772 sb1250_duart_driver.open = duart_open;
773 sb1250_duart_driver.close = duart_close;
774 sb1250_duart_driver.write = duart_write;
775 sb1250_duart_driver.put_char = duart_put_char;
776 sb1250_duart_driver.write_room = duart_write_room;
777 sb1250_duart_driver.flush_chars = duart_flush_chars;
778 sb1250_duart_driver.chars_in_buffer = duart_chars_in_buffer;
779 sb1250_duart_driver.flush_buffer = duart_flush_buffer;
780 sb1250_duart_driver.ioctl = duart_ioctl;
781 sb1250_duart_driver.set_termios = duart_set_termios;
782 sb1250_duart_driver.stop = duart_stop;
783 sb1250_duart_driver.start = duart_start;
784 sb1250_duart_driver.hangup = duart_hangup;
785 sb1250_duart_driver.wait_until_sent = duart_wait_until_sent;
786
787 sb1250_duart_callout_driver = sb1250_duart_driver;
788#ifdef CONFIG_DEVFS_FS
789 sb1250_duart_callout_driver.name = "cua/%d";
790#else
791 sb1250_duart_callout_driver.name = "cua";
792#endif
793 sb1250_duart_callout_driver.major = TTYAUX_MAJOR;
794 sb1250_duart_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
795
796 for (i=0; i<DUART_MAX_LINE; i++) {
797 uart_state_t *port = uart_states + i;
798
799 if (!sb1250_duart_present[i])
800 continue;
801
802 init_duart_port(port, i);
803 spin_lock_init(&port->outp_lock);
804 duart_mask_ints(i, M_DUART_IMR_ALL);
805 if (request_irq(K_INT_UART_0+i, duart_int, 0, "uart", port)) {
806 panic("Couldn't get uart0 interrupt line");
807 }
808 out64(M_DUART_RX_EN|M_DUART_TX_EN,
809 IO_SPACE_BASE | A_DUART_CHANREG(i, R_DUART_CMD));
810 duart_set_cflag(i, DEFAULT_CFLAGS);
811 }
812
813
814
815 if (tty_register_driver(&sb1250_duart_driver)) {
816 printk(KERN_ERR "Couldn't register sb1250 duart serial driver\n");
817 }
818 if (tty_register_driver(&sb1250_duart_callout_driver)) {
819 printk(KERN_ERR "Couldn't register sb1250 duart callout driver\n");
820 }
821 return 0;
822}
823
824
825static void __exit sb1250_duart_fini(void)
826{
827 unsigned long flags;
828 int i;
829 int ret;
830
831 save_and_cli(flags);
832 ret = tty_unregister_driver(&sb1250_duart_callout_driver);
833 if (ret) {
834 printk(KERN_ERR "Unable to unregister sb1250 duart callout driver (%d)\n", ret);
835 }
836 ret = tty_unregister_driver(&sb1250_duart_driver);
837 if (ret) {
838 printk(KERN_ERR "Unable to unregister sb1250 duart serial driver (%d)\n", ret);
839 }
840 for (i=0; i<DUART_MAX_LINE; i++) {
841 if (!sb1250_duart_present[i])
842 continue;
843 free_irq(K_INT_UART_0+i, &uart_states[i]);
844 disable_irq(K_INT_UART_0+i);
845 }
846 restore_flags(flags);
847}
848
849module_init(sb1250_duart_init);
850module_exit(sb1250_duart_fini);
851MODULE_DESCRIPTION("SB1250 Duart serial driver");
852MODULE_AUTHOR("Justin Carlson, Broadcom Corp.");
853
854#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE
855
856
857
858
859
860
861
862
863void serial_outc(unsigned char c, int line)
864{
865 uart_state_t *port = uart_states + line;
866 while (!(READ_SERCSR(port->status, line) & M_DUART_TX_RDY)) ;
867 WRITE_SERCSR(c, port->tx_hold, line);
868 while (!(READ_SERCSR(port->status, port->line) & M_DUART_TX_EMT)) ;
869}
870
871static void ser_console_write(struct console *cons, const char *s,
872 unsigned int count)
873{
874 int line = cons->index;
875 uart_state_t *port = uart_states + line;
876 u32 imr;
877
878 imr = READ_SERCSR(port->imr, line);
879 WRITE_SERCSR(0, port->imr, line);
880 while (count--) {
881 if (*s == '\n')
882 serial_outc('\r', line);
883 serial_outc(*s++, line);
884 }
885 WRITE_SERCSR(imr, port->imr, line);
886}
887
888static kdev_t ser_console_device(struct console *c)
889{
890 return MKDEV(TTY_MAJOR, SB1250_DUART_MINOR_BASE + c->index);
891}
892
893static int ser_console_setup(struct console *cons, char *str)
894{
895 int i;
896
897 for (i=0; i<DUART_MAX_LINE; i++) {
898 uart_state_t *port = uart_states + i;
899
900 if (!sb1250_duart_present[i])
901 continue;
902
903 init_duart_port(port, i);
904#if SIBYTE_1956_WAR
905 last_mode1[i] = V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8;
906#endif
907 WRITE_SERCSR(V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8,
908 port->mode_1, i);
909 WRITE_SERCSR(M_DUART_STOP_BIT_LEN_1,
910 port->mode_2, i);
911 WRITE_SERCSR(V_DUART_BAUD_RATE(115200),
912 port->clk_sel, i);
913 WRITE_SERCSR(M_DUART_RX_EN|M_DUART_TX_EN,
914 port->cmd, i);
915 }
916 return 0;
917}
918
919static struct console sb1250_ser_cons = {
920 name: "duart",
921 write: ser_console_write,
922 device: ser_console_device,
923 setup: ser_console_setup,
924 flags: CON_PRINTBUFFER,
925 index: -1,
926};
927
928void __init sb1250_serial_console_init(void)
929{
930 register_console(&sb1250_ser_cons);
931}
932
933#endif
934