diff options
author | David S. Miller <davem@davemloft.net> | 2005-05-11 14:34:32 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-05-11 14:34:32 -0400 |
commit | e4fdee8e3b41239242a8f421a28736ef8e08ca55 (patch) | |
tree | d2040221acc9fbd2f24f7670d0edfaba425d376c /drivers | |
parent | 88d7bd8cb9eb8d64bf7997600b0d64f7834047c5 (diff) |
[SUNSAB]: Defer register updates until transmitter is idle.
The chip can emit garbage characters if we touch the
settings while characters are going out.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/serial/sunsab.c | 109 | ||||
-rw-r--r-- | drivers/serial/sunsab.h | 1 |
2 files changed, 72 insertions, 38 deletions
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 39b788d95e39..10e2990a40d4 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c | |||
@@ -61,6 +61,16 @@ struct uart_sunsab_port { | |||
61 | unsigned char pvr_dtr_bit; /* Which PVR bit is DTR */ | 61 | unsigned char pvr_dtr_bit; /* Which PVR bit is DTR */ |
62 | unsigned char pvr_dsr_bit; /* Which PVR bit is DSR */ | 62 | unsigned char pvr_dsr_bit; /* Which PVR bit is DSR */ |
63 | int type; /* SAB82532 version */ | 63 | int type; /* SAB82532 version */ |
64 | |||
65 | /* Setting configuration bits while the transmitter is active | ||
66 | * can cause garbage characters to get emitted by the chip. | ||
67 | * Therefore, we cache such writes here and do the real register | ||
68 | * write the next time the transmitter becomes idle. | ||
69 | */ | ||
70 | unsigned int cached_ebrg; | ||
71 | unsigned char cached_mode; | ||
72 | unsigned char cached_pvr; | ||
73 | unsigned char cached_dafo; | ||
64 | }; | 74 | }; |
65 | 75 | ||
66 | /* | 76 | /* |
@@ -236,6 +246,7 @@ receive_chars(struct uart_sunsab_port *up, | |||
236 | } | 246 | } |
237 | 247 | ||
238 | static void sunsab_stop_tx(struct uart_port *, unsigned int); | 248 | static void sunsab_stop_tx(struct uart_port *, unsigned int); |
249 | static void sunsab_tx_idle(struct uart_sunsab_port *); | ||
239 | 250 | ||
240 | static void transmit_chars(struct uart_sunsab_port *up, | 251 | static void transmit_chars(struct uart_sunsab_port *up, |
241 | union sab82532_irq_status *stat) | 252 | union sab82532_irq_status *stat) |
@@ -258,6 +269,7 @@ static void transmit_chars(struct uart_sunsab_port *up, | |||
258 | return; | 269 | return; |
259 | 270 | ||
260 | set_bit(SAB82532_XPR, &up->irqflags); | 271 | set_bit(SAB82532_XPR, &up->irqflags); |
272 | sunsab_tx_idle(up); | ||
261 | 273 | ||
262 | if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { | 274 | if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { |
263 | up->interrupt_mask1 |= SAB82532_IMR1_XPR; | 275 | up->interrupt_mask1 |= SAB82532_IMR1_XPR; |
@@ -397,21 +409,21 @@ static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl) | |||
397 | struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; | 409 | struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; |
398 | 410 | ||
399 | if (mctrl & TIOCM_RTS) { | 411 | if (mctrl & TIOCM_RTS) { |
400 | writeb(readb(&up->regs->rw.mode) & ~SAB82532_MODE_FRTS, | 412 | up->cached_mode &= ~SAB82532_MODE_FRTS; |
401 | &up->regs->rw.mode); | 413 | up->cached_mode |= SAB82532_MODE_RTS; |
402 | writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS, | ||
403 | &up->regs->rw.mode); | ||
404 | } else { | 414 | } else { |
405 | writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_FRTS, | 415 | up->cached_mode |= (SAB82532_MODE_FRTS | |
406 | &up->regs->rw.mode); | 416 | SAB82532_MODE_RTS); |
407 | writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS, | ||
408 | &up->regs->rw.mode); | ||
409 | } | 417 | } |
410 | if (mctrl & TIOCM_DTR) { | 418 | if (mctrl & TIOCM_DTR) { |
411 | writeb(readb(&up->regs->rw.pvr) & ~(up->pvr_dtr_bit), &up->regs->rw.pvr); | 419 | up->cached_pvr &= ~(up->pvr_dtr_bit); |
412 | } else { | 420 | } else { |
413 | writeb(readb(&up->regs->rw.pvr) | up->pvr_dtr_bit, &up->regs->rw.pvr); | 421 | up->cached_pvr |= up->pvr_dtr_bit; |
414 | } | 422 | } |
423 | |||
424 | set_bit(SAB82532_REGS_PENDING, &up->irqflags); | ||
425 | if (test_bit(SAB82532_XPR, &up->irqflags)) | ||
426 | sunsab_tx_idle(up); | ||
415 | } | 427 | } |
416 | 428 | ||
417 | /* port->lock is not held. */ | 429 | /* port->lock is not held. */ |
@@ -450,6 +462,25 @@ static void sunsab_stop_tx(struct uart_port *port, unsigned int tty_stop) | |||
450 | } | 462 | } |
451 | 463 | ||
452 | /* port->lock held by caller. */ | 464 | /* port->lock held by caller. */ |
465 | static void sunsab_tx_idle(struct uart_sunsab_port *up) | ||
466 | { | ||
467 | if (test_bit(SAB82532_REGS_PENDING, &up->irqflags)) { | ||
468 | u8 tmp; | ||
469 | |||
470 | clear_bit(SAB82532_REGS_PENDING, &up->irqflags); | ||
471 | writeb(up->cached_mode, &up->regs->rw.mode); | ||
472 | writeb(up->cached_pvr, &up->regs->rw.pvr); | ||
473 | writeb(up->cached_dafo, &up->regs->w.dafo); | ||
474 | |||
475 | writeb(up->cached_ebrg & 0xff, &up->regs->w.bgr); | ||
476 | tmp = readb(&up->regs->rw.ccr2); | ||
477 | tmp &= ~0xc0; | ||
478 | tmp |= (up->cached_ebrg >> 2) & 0xc0; | ||
479 | writeb(tmp, &up->regs->rw.ccr2); | ||
480 | } | ||
481 | } | ||
482 | |||
483 | /* port->lock held by caller. */ | ||
453 | static void sunsab_start_tx(struct uart_port *port, unsigned int tty_start) | 484 | static void sunsab_start_tx(struct uart_port *port, unsigned int tty_start) |
454 | { | 485 | { |
455 | struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; | 486 | struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; |
@@ -517,12 +548,16 @@ static void sunsab_break_ctl(struct uart_port *port, int break_state) | |||
517 | 548 | ||
518 | spin_lock_irqsave(&up->port.lock, flags); | 549 | spin_lock_irqsave(&up->port.lock, flags); |
519 | 550 | ||
520 | val = readb(&up->regs->rw.dafo); | 551 | val = up->cached_dafo; |
521 | if (break_state) | 552 | if (break_state) |
522 | val |= SAB82532_DAFO_XBRK; | 553 | val |= SAB82532_DAFO_XBRK; |
523 | else | 554 | else |
524 | val &= ~SAB82532_DAFO_XBRK; | 555 | val &= ~SAB82532_DAFO_XBRK; |
525 | writeb(val, &up->regs->rw.dafo); | 556 | up->cached_dafo = val; |
557 | |||
558 | set_bit(SAB82532_REGS_PENDING, &up->irqflags); | ||
559 | if (test_bit(SAB82532_XPR, &up->irqflags)) | ||
560 | sunsab_tx_idle(up); | ||
526 | 561 | ||
527 | spin_unlock_irqrestore(&up->port.lock, flags); | 562 | spin_unlock_irqrestore(&up->port.lock, flags); |
528 | } | 563 | } |
@@ -566,8 +601,9 @@ static int sunsab_startup(struct uart_port *port) | |||
566 | SAB82532_CCR2_TOE, &up->regs->w.ccr2); | 601 | SAB82532_CCR2_TOE, &up->regs->w.ccr2); |
567 | writeb(0, &up->regs->w.ccr3); | 602 | writeb(0, &up->regs->w.ccr3); |
568 | writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &up->regs->w.ccr4); | 603 | writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &up->regs->w.ccr4); |
569 | writeb(SAB82532_MODE_RTS | SAB82532_MODE_FCTS | | 604 | up->cached_mode = (SAB82532_MODE_RTS | SAB82532_MODE_FCTS | |
570 | SAB82532_MODE_RAC, &up->regs->w.mode); | 605 | SAB82532_MODE_RAC); |
606 | writeb(up->cached_mode, &up->regs->w.mode); | ||
571 | writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc); | 607 | writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc); |
572 | 608 | ||
573 | tmp = readb(&up->regs->rw.ccr0); | 609 | tmp = readb(&up->regs->rw.ccr0); |
@@ -598,7 +634,6 @@ static void sunsab_shutdown(struct uart_port *port) | |||
598 | { | 634 | { |
599 | struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; | 635 | struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; |
600 | unsigned long flags; | 636 | unsigned long flags; |
601 | unsigned char tmp; | ||
602 | 637 | ||
603 | spin_lock_irqsave(&up->port.lock, flags); | 638 | spin_lock_irqsave(&up->port.lock, flags); |
604 | 639 | ||
@@ -609,14 +644,13 @@ static void sunsab_shutdown(struct uart_port *port) | |||
609 | writeb(up->interrupt_mask1, &up->regs->w.imr1); | 644 | writeb(up->interrupt_mask1, &up->regs->w.imr1); |
610 | 645 | ||
611 | /* Disable break condition */ | 646 | /* Disable break condition */ |
612 | tmp = readb(&up->regs->rw.dafo); | 647 | up->cached_dafo = readb(&up->regs->rw.dafo); |
613 | tmp &= ~SAB82532_DAFO_XBRK; | 648 | up->cached_dafo &= ~SAB82532_DAFO_XBRK; |
614 | writeb(tmp, &up->regs->rw.dafo); | 649 | writeb(up->cached_dafo, &up->regs->rw.dafo); |
615 | 650 | ||
616 | /* Disable Receiver */ | 651 | /* Disable Receiver */ |
617 | tmp = readb(&up->regs->rw.mode); | 652 | up->cached_mode &= ~SAB82532_MODE_RAC; |
618 | tmp &= ~SAB82532_MODE_RAC; | 653 | writeb(up->cached_mode, &up->regs->rw.mode); |
619 | writeb(tmp, &up->regs->rw.mode); | ||
620 | 654 | ||
621 | /* | 655 | /* |
622 | * XXX FIXME | 656 | * XXX FIXME |
@@ -685,7 +719,6 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla | |||
685 | unsigned int iflag, unsigned int baud, | 719 | unsigned int iflag, unsigned int baud, |
686 | unsigned int quot) | 720 | unsigned int quot) |
687 | { | 721 | { |
688 | unsigned int ebrg; | ||
689 | unsigned char dafo; | 722 | unsigned char dafo; |
690 | int bits, n, m; | 723 | int bits, n, m; |
691 | 724 | ||
@@ -714,10 +747,11 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla | |||
714 | } else { | 747 | } else { |
715 | dafo |= SAB82532_DAFO_PAR_EVEN; | 748 | dafo |= SAB82532_DAFO_PAR_EVEN; |
716 | } | 749 | } |
750 | up->cached_dafo = dafo; | ||
717 | 751 | ||
718 | calc_ebrg(baud, &n, &m); | 752 | calc_ebrg(baud, &n, &m); |
719 | 753 | ||
720 | ebrg = n | (m << 6); | 754 | up->cached_ebrg = n | (m << 6); |
721 | 755 | ||
722 | up->tec_timeout = (10 * 1000000) / baud; | 756 | up->tec_timeout = (10 * 1000000) / baud; |
723 | up->cec_timeout = up->tec_timeout >> 2; | 757 | up->cec_timeout = up->tec_timeout >> 2; |
@@ -770,16 +804,13 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla | |||
770 | uart_update_timeout(&up->port, cflag, | 804 | uart_update_timeout(&up->port, cflag, |
771 | (up->port.uartclk / (16 * quot))); | 805 | (up->port.uartclk / (16 * quot))); |
772 | 806 | ||
773 | /* Now bang the new settings into the chip. */ | 807 | /* Now schedule a register update when the chip's |
774 | sunsab_cec_wait(up); | 808 | * transmitter is idle. |
775 | sunsab_tec_wait(up); | 809 | */ |
776 | writeb(dafo, &up->regs->w.dafo); | 810 | up->cached_mode |= SAB82532_MODE_RAC; |
777 | writeb(ebrg & 0xff, &up->regs->w.bgr); | 811 | set_bit(SAB82532_REGS_PENDING, &up->irqflags); |
778 | writeb((readb(&up->regs->rw.ccr2) & ~0xc0) | ((ebrg >> 2) & 0xc0), | 812 | if (test_bit(SAB82532_XPR, &up->irqflags)) |
779 | &up->regs->rw.ccr2); | 813 | sunsab_tx_idle(up); |
780 | |||
781 | writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RAC, &up->regs->rw.mode); | ||
782 | |||
783 | } | 814 | } |
784 | 815 | ||
785 | /* port->lock is not held. */ | 816 | /* port->lock is not held. */ |
@@ -1084,11 +1115,13 @@ static void __init sunsab_init_hw(void) | |||
1084 | up->pvr_dsr_bit = (1 << 3); | 1115 | up->pvr_dsr_bit = (1 << 3); |
1085 | up->pvr_dtr_bit = (1 << 2); | 1116 | up->pvr_dtr_bit = (1 << 2); |
1086 | } | 1117 | } |
1087 | writeb((1 << 1) | (1 << 2) | (1 << 4), &up->regs->w.pvr); | 1118 | up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4); |
1088 | writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_FRTS, | 1119 | writeb(up->cached_pvr, &up->regs->w.pvr); |
1089 | &up->regs->rw.mode); | 1120 | up->cached_mode = readb(&up->regs->rw.mode); |
1090 | writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS, | 1121 | up->cached_mode |= SAB82532_MODE_FRTS; |
1091 | &up->regs->rw.mode); | 1122 | writeb(up->cached_mode, &up->regs->rw.mode); |
1123 | up->cached_mode |= SAB82532_MODE_RTS; | ||
1124 | writeb(up->cached_mode, &up->regs->rw.mode); | ||
1092 | 1125 | ||
1093 | up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; | 1126 | up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; |
1094 | up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; | 1127 | up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; |
diff --git a/drivers/serial/sunsab.h b/drivers/serial/sunsab.h index 686086fcbbf5..b78e1f7b8050 100644 --- a/drivers/serial/sunsab.h +++ b/drivers/serial/sunsab.h | |||
@@ -126,6 +126,7 @@ union sab82532_irq_status { | |||
126 | /* irqflags bits */ | 126 | /* irqflags bits */ |
127 | #define SAB82532_ALLS 0x00000001 | 127 | #define SAB82532_ALLS 0x00000001 |
128 | #define SAB82532_XPR 0x00000002 | 128 | #define SAB82532_XPR 0x00000002 |
129 | #define SAB82532_REGS_PENDING 0x00000004 | ||
129 | 130 | ||
130 | /* RFIFO Status Byte */ | 131 | /* RFIFO Status Byte */ |
131 | #define SAB82532_RSTAT_PE 0x80 | 132 | #define SAB82532_RSTAT_PE 0x80 |