Commit e4fdee8e authored by David S. Miller's avatar David S. Miller

[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: default avatarDavid S. Miller <davem@davemloft.net>
parent 88d7bd8c
...@@ -61,6 +61,16 @@ struct uart_sunsab_port { ...@@ -61,6 +61,16 @@ struct uart_sunsab_port {
unsigned char pvr_dtr_bit; /* Which PVR bit is DTR */ unsigned char pvr_dtr_bit; /* Which PVR bit is DTR */
unsigned char pvr_dsr_bit; /* Which PVR bit is DSR */ unsigned char pvr_dsr_bit; /* Which PVR bit is DSR */
int type; /* SAB82532 version */ int type; /* SAB82532 version */
/* Setting configuration bits while the transmitter is active
* can cause garbage characters to get emitted by the chip.
* Therefore, we cache such writes here and do the real register
* write the next time the transmitter becomes idle.
*/
unsigned int cached_ebrg;
unsigned char cached_mode;
unsigned char cached_pvr;
unsigned char cached_dafo;
}; };
/* /*
...@@ -236,6 +246,7 @@ receive_chars(struct uart_sunsab_port *up, ...@@ -236,6 +246,7 @@ receive_chars(struct uart_sunsab_port *up,
} }
static void sunsab_stop_tx(struct uart_port *, unsigned int); static void sunsab_stop_tx(struct uart_port *, unsigned int);
static void sunsab_tx_idle(struct uart_sunsab_port *);
static void transmit_chars(struct uart_sunsab_port *up, static void transmit_chars(struct uart_sunsab_port *up,
union sab82532_irq_status *stat) union sab82532_irq_status *stat)
...@@ -258,6 +269,7 @@ static void transmit_chars(struct uart_sunsab_port *up, ...@@ -258,6 +269,7 @@ static void transmit_chars(struct uart_sunsab_port *up,
return; return;
set_bit(SAB82532_XPR, &up->irqflags); set_bit(SAB82532_XPR, &up->irqflags);
sunsab_tx_idle(up);
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
up->interrupt_mask1 |= SAB82532_IMR1_XPR; up->interrupt_mask1 |= SAB82532_IMR1_XPR;
...@@ -397,21 +409,21 @@ static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl) ...@@ -397,21 +409,21 @@ static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl)
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
if (mctrl & TIOCM_RTS) { if (mctrl & TIOCM_RTS) {
writeb(readb(&up->regs->rw.mode) & ~SAB82532_MODE_FRTS, up->cached_mode &= ~SAB82532_MODE_FRTS;
&up->regs->rw.mode); up->cached_mode |= SAB82532_MODE_RTS;
writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS,
&up->regs->rw.mode);
} else { } else {
writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_FRTS, up->cached_mode |= (SAB82532_MODE_FRTS |
&up->regs->rw.mode); SAB82532_MODE_RTS);
writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS,
&up->regs->rw.mode);
} }
if (mctrl & TIOCM_DTR) { if (mctrl & TIOCM_DTR) {
writeb(readb(&up->regs->rw.pvr) & ~(up->pvr_dtr_bit), &up->regs->rw.pvr); up->cached_pvr &= ~(up->pvr_dtr_bit);
} else { } else {
writeb(readb(&up->regs->rw.pvr) | up->pvr_dtr_bit, &up->regs->rw.pvr); up->cached_pvr |= up->pvr_dtr_bit;
} }
set_bit(SAB82532_REGS_PENDING, &up->irqflags);
if (test_bit(SAB82532_XPR, &up->irqflags))
sunsab_tx_idle(up);
} }
/* port->lock is not held. */ /* port->lock is not held. */
...@@ -449,6 +461,25 @@ static void sunsab_stop_tx(struct uart_port *port, unsigned int tty_stop) ...@@ -449,6 +461,25 @@ static void sunsab_stop_tx(struct uart_port *port, unsigned int tty_stop)
writeb(up->interrupt_mask1, &up->regs->w.imr1); writeb(up->interrupt_mask1, &up->regs->w.imr1);
} }
/* port->lock held by caller. */
static void sunsab_tx_idle(struct uart_sunsab_port *up)
{
if (test_bit(SAB82532_REGS_PENDING, &up->irqflags)) {
u8 tmp;
clear_bit(SAB82532_REGS_PENDING, &up->irqflags);
writeb(up->cached_mode, &up->regs->rw.mode);
writeb(up->cached_pvr, &up->regs->rw.pvr);
writeb(up->cached_dafo, &up->regs->w.dafo);
writeb(up->cached_ebrg & 0xff, &up->regs->w.bgr);
tmp = readb(&up->regs->rw.ccr2);
tmp &= ~0xc0;
tmp |= (up->cached_ebrg >> 2) & 0xc0;
writeb(tmp, &up->regs->rw.ccr2);
}
}
/* port->lock held by caller. */ /* port->lock held by caller. */
static void sunsab_start_tx(struct uart_port *port, unsigned int tty_start) static void sunsab_start_tx(struct uart_port *port, unsigned int tty_start)
{ {
...@@ -517,12 +548,16 @@ static void sunsab_break_ctl(struct uart_port *port, int break_state) ...@@ -517,12 +548,16 @@ static void sunsab_break_ctl(struct uart_port *port, int break_state)
spin_lock_irqsave(&up->port.lock, flags); spin_lock_irqsave(&up->port.lock, flags);
val = readb(&up->regs->rw.dafo); val = up->cached_dafo;
if (break_state) if (break_state)
val |= SAB82532_DAFO_XBRK; val |= SAB82532_DAFO_XBRK;
else else
val &= ~SAB82532_DAFO_XBRK; val &= ~SAB82532_DAFO_XBRK;
writeb(val, &up->regs->rw.dafo); up->cached_dafo = val;
set_bit(SAB82532_REGS_PENDING, &up->irqflags);
if (test_bit(SAB82532_XPR, &up->irqflags))
sunsab_tx_idle(up);
spin_unlock_irqrestore(&up->port.lock, flags); spin_unlock_irqrestore(&up->port.lock, flags);
} }
...@@ -566,8 +601,9 @@ static int sunsab_startup(struct uart_port *port) ...@@ -566,8 +601,9 @@ static int sunsab_startup(struct uart_port *port)
SAB82532_CCR2_TOE, &up->regs->w.ccr2); SAB82532_CCR2_TOE, &up->regs->w.ccr2);
writeb(0, &up->regs->w.ccr3); writeb(0, &up->regs->w.ccr3);
writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &up->regs->w.ccr4); writeb(SAB82532_CCR4_MCK4 | SAB82532_CCR4_EBRG, &up->regs->w.ccr4);
writeb(SAB82532_MODE_RTS | SAB82532_MODE_FCTS | up->cached_mode = (SAB82532_MODE_RTS | SAB82532_MODE_FCTS |
SAB82532_MODE_RAC, &up->regs->w.mode); SAB82532_MODE_RAC);
writeb(up->cached_mode, &up->regs->w.mode);
writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc); writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc);
tmp = readb(&up->regs->rw.ccr0); tmp = readb(&up->regs->rw.ccr0);
...@@ -598,7 +634,6 @@ static void sunsab_shutdown(struct uart_port *port) ...@@ -598,7 +634,6 @@ static void sunsab_shutdown(struct uart_port *port)
{ {
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
unsigned long flags; unsigned long flags;
unsigned char tmp;
spin_lock_irqsave(&up->port.lock, flags); spin_lock_irqsave(&up->port.lock, flags);
...@@ -609,14 +644,13 @@ static void sunsab_shutdown(struct uart_port *port) ...@@ -609,14 +644,13 @@ static void sunsab_shutdown(struct uart_port *port)
writeb(up->interrupt_mask1, &up->regs->w.imr1); writeb(up->interrupt_mask1, &up->regs->w.imr1);
/* Disable break condition */ /* Disable break condition */
tmp = readb(&up->regs->rw.dafo); up->cached_dafo = readb(&up->regs->rw.dafo);
tmp &= ~SAB82532_DAFO_XBRK; up->cached_dafo &= ~SAB82532_DAFO_XBRK;
writeb(tmp, &up->regs->rw.dafo); writeb(up->cached_dafo, &up->regs->rw.dafo);
/* Disable Receiver */ /* Disable Receiver */
tmp = readb(&up->regs->rw.mode); up->cached_mode &= ~SAB82532_MODE_RAC;
tmp &= ~SAB82532_MODE_RAC; writeb(up->cached_mode, &up->regs->rw.mode);
writeb(tmp, &up->regs->rw.mode);
/* /*
* XXX FIXME * XXX FIXME
...@@ -685,7 +719,6 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla ...@@ -685,7 +719,6 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla
unsigned int iflag, unsigned int baud, unsigned int iflag, unsigned int baud,
unsigned int quot) unsigned int quot)
{ {
unsigned int ebrg;
unsigned char dafo; unsigned char dafo;
int bits, n, m; int bits, n, m;
...@@ -714,10 +747,11 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla ...@@ -714,10 +747,11 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla
} else { } else {
dafo |= SAB82532_DAFO_PAR_EVEN; dafo |= SAB82532_DAFO_PAR_EVEN;
} }
up->cached_dafo = dafo;
calc_ebrg(baud, &n, &m); calc_ebrg(baud, &n, &m);
ebrg = n | (m << 6); up->cached_ebrg = n | (m << 6);
up->tec_timeout = (10 * 1000000) / baud; up->tec_timeout = (10 * 1000000) / baud;
up->cec_timeout = up->tec_timeout >> 2; 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,16 +804,13 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla
uart_update_timeout(&up->port, cflag, uart_update_timeout(&up->port, cflag,
(up->port.uartclk / (16 * quot))); (up->port.uartclk / (16 * quot)));
/* Now bang the new settings into the chip. */ /* Now schedule a register update when the chip's
sunsab_cec_wait(up); * transmitter is idle.
sunsab_tec_wait(up); */
writeb(dafo, &up->regs->w.dafo); up->cached_mode |= SAB82532_MODE_RAC;
writeb(ebrg & 0xff, &up->regs->w.bgr); set_bit(SAB82532_REGS_PENDING, &up->irqflags);
writeb((readb(&up->regs->rw.ccr2) & ~0xc0) | ((ebrg >> 2) & 0xc0), if (test_bit(SAB82532_XPR, &up->irqflags))
&up->regs->rw.ccr2); sunsab_tx_idle(up);
writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RAC, &up->regs->rw.mode);
} }
/* port->lock is not held. */ /* port->lock is not held. */
...@@ -1084,11 +1115,13 @@ static void __init sunsab_init_hw(void) ...@@ -1084,11 +1115,13 @@ static void __init sunsab_init_hw(void)
up->pvr_dsr_bit = (1 << 3); up->pvr_dsr_bit = (1 << 3);
up->pvr_dtr_bit = (1 << 2); up->pvr_dtr_bit = (1 << 2);
} }
writeb((1 << 1) | (1 << 2) | (1 << 4), &up->regs->w.pvr); up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4);
writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_FRTS, writeb(up->cached_pvr, &up->regs->w.pvr);
&up->regs->rw.mode); up->cached_mode = readb(&up->regs->rw.mode);
writeb(readb(&up->regs->rw.mode) | SAB82532_MODE_RTS, up->cached_mode |= SAB82532_MODE_FRTS;
&up->regs->rw.mode); writeb(up->cached_mode, &up->regs->rw.mode);
up->cached_mode |= SAB82532_MODE_RTS;
writeb(up->cached_mode, &up->regs->rw.mode);
up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;
up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;
......
...@@ -126,6 +126,7 @@ union sab82532_irq_status { ...@@ -126,6 +126,7 @@ union sab82532_irq_status {
/* irqflags bits */ /* irqflags bits */
#define SAB82532_ALLS 0x00000001 #define SAB82532_ALLS 0x00000001
#define SAB82532_XPR 0x00000002 #define SAB82532_XPR 0x00000002
#define SAB82532_REGS_PENDING 0x00000004
/* RFIFO Status Byte */ /* RFIFO Status Byte */
#define SAB82532_RSTAT_PE 0x80 #define SAB82532_RSTAT_PE 0x80
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment