|
|
|
@@ -444,25 +444,53 @@ struct mn10300_serial_int mn10300_serial_int_tbl[NR_IRQS];
|
|
|
|
|
|
|
|
|
|
static void mn10300_serial_dis_tx_intr(struct mn10300_serial_port *port)
|
|
|
|
|
{
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
int retries = 100;
|
|
|
|
|
u16 x;
|
|
|
|
|
|
|
|
|
|
flags = arch_local_cli_save();
|
|
|
|
|
*port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
|
|
|
|
|
x = *port->tx_icr;
|
|
|
|
|
arch_local_irq_restore(flags);
|
|
|
|
|
/* nothing to do if irq isn't set up */
|
|
|
|
|
if (!mn10300_serial_int_tbl[port->tx_irq].port)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
port->tx_flags |= MNSCx_TX_STOP;
|
|
|
|
|
mb();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Here we wait for the irq to be disabled. Either it already is
|
|
|
|
|
* disabled or we wait some number of retries for the VDMA handler
|
|
|
|
|
* to disable it. The retries give the VDMA handler enough time to
|
|
|
|
|
* run to completion if it was already in progress. If the VDMA IRQ
|
|
|
|
|
* is enabled but the handler is not yet running when arrive here,
|
|
|
|
|
* the STOP flag will prevent the handler from conflicting with the
|
|
|
|
|
* driver code following this loop.
|
|
|
|
|
*/
|
|
|
|
|
while ((*port->tx_icr & GxICR_ENABLE) && retries-- > 0)
|
|
|
|
|
;
|
|
|
|
|
if (retries <= 0) {
|
|
|
|
|
*port->tx_icr =
|
|
|
|
|
NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
|
|
|
|
|
x = *port->tx_icr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mn10300_serial_en_tx_intr(struct mn10300_serial_port *port)
|
|
|
|
|
{
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
u16 x;
|
|
|
|
|
|
|
|
|
|
flags = arch_local_cli_save();
|
|
|
|
|
/* nothing to do if irq isn't set up */
|
|
|
|
|
if (!mn10300_serial_int_tbl[port->tx_irq].port)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* stop vdma irq if not already stopped */
|
|
|
|
|
if (!(port->tx_flags & MNSCx_TX_STOP))
|
|
|
|
|
mn10300_serial_dis_tx_intr(port);
|
|
|
|
|
|
|
|
|
|
port->tx_flags &= ~MNSCx_TX_STOP;
|
|
|
|
|
mb();
|
|
|
|
|
|
|
|
|
|
*port->tx_icr =
|
|
|
|
|
NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL) | GxICR_ENABLE;
|
|
|
|
|
NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL) |
|
|
|
|
|
GxICR_ENABLE | GxICR_REQUEST | GxICR_DETECT;
|
|
|
|
|
x = *port->tx_icr;
|
|
|
|
|
arch_local_irq_restore(flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mn10300_serial_dis_rx_intr(struct mn10300_serial_port *port)
|
|
|
|
@@ -807,8 +835,6 @@ static void mn10300_serial_start_tx(struct uart_port *_port)
|
|
|
|
|
struct mn10300_serial_port *port =
|
|
|
|
|
container_of(_port, struct mn10300_serial_port, uart);
|
|
|
|
|
|
|
|
|
|
u16 x;
|
|
|
|
|
|
|
|
|
|
_enter("%s{%lu}",
|
|
|
|
|
port->name,
|
|
|
|
|
CIRC_CNT(&port->uart.state->xmit.head,
|
|
|
|
@@ -816,14 +842,7 @@ static void mn10300_serial_start_tx(struct uart_port *_port)
|
|
|
|
|
UART_XMIT_SIZE));
|
|
|
|
|
|
|
|
|
|
/* kick the virtual DMA controller */
|
|
|
|
|
arch_local_cli();
|
|
|
|
|
x = *port->tx_icr;
|
|
|
|
|
x |= GxICR_ENABLE;
|
|
|
|
|
|
|
|
|
|
if (*port->_status & SC01STR_TBF)
|
|
|
|
|
x &= ~(GxICR_REQUEST | GxICR_DETECT);
|
|
|
|
|
else
|
|
|
|
|
x |= GxICR_REQUEST | GxICR_DETECT;
|
|
|
|
|
mn10300_serial_en_tx_intr(port);
|
|
|
|
|
|
|
|
|
|
_debug("CTR=%04hx ICR=%02hx STR=%04x TMD=%02hx TBR=%04hx ICR=%04hx",
|
|
|
|
|
*port->_control, *port->_intr, *port->_status,
|
|
|
|
@@ -831,10 +850,6 @@ static void mn10300_serial_start_tx(struct uart_port *_port)
|
|
|
|
|
(port->div_timer == MNSCx_DIV_TIMER_8BIT) ?
|
|
|
|
|
*(volatile u8 *)port->_tmxbr : *port->_tmxbr,
|
|
|
|
|
*port->tx_icr);
|
|
|
|
|
|
|
|
|
|
*port->tx_icr = x;
|
|
|
|
|
x = *port->tx_icr;
|
|
|
|
|
arch_local_sti();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -844,13 +859,17 @@ static void mn10300_serial_send_xchar(struct uart_port *_port, char ch)
|
|
|
|
|
{
|
|
|
|
|
struct mn10300_serial_port *port =
|
|
|
|
|
container_of(_port, struct mn10300_serial_port, uart);
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
|
|
_enter("%s,%02x", port->name, ch);
|
|
|
|
|
|
|
|
|
|
if (likely(port->gdbstub)) {
|
|
|
|
|
port->tx_xchar = ch;
|
|
|
|
|
if (ch)
|
|
|
|
|
if (ch) {
|
|
|
|
|
spin_lock_irqsave(&port->uart.lock, flags);
|
|
|
|
|
mn10300_serial_en_tx_intr(port);
|
|
|
|
|
spin_unlock_irqrestore(&port->uart.lock, flags);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -911,18 +930,21 @@ static void mn10300_serial_break_ctl(struct uart_port *_port, int ctl)
|
|
|
|
|
{
|
|
|
|
|
struct mn10300_serial_port *port =
|
|
|
|
|
container_of(_port, struct mn10300_serial_port, uart);
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
|
|
_enter("%s,%d", port->name, ctl);
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&port->uart.lock, flags);
|
|
|
|
|
if (ctl) {
|
|
|
|
|
/* tell the virtual DMA handler to assert BREAK */
|
|
|
|
|
port->tx_break = 1;
|
|
|
|
|
port->tx_flags |= MNSCx_TX_BREAK;
|
|
|
|
|
mn10300_serial_en_tx_intr(port);
|
|
|
|
|
} else {
|
|
|
|
|
port->tx_break = 0;
|
|
|
|
|
port->tx_flags &= ~MNSCx_TX_BREAK;
|
|
|
|
|
*port->_control &= ~SC01CTR_BKE;
|
|
|
|
|
mn10300_serial_en_tx_intr(port);
|
|
|
|
|
}
|
|
|
|
|
spin_unlock_irqrestore(&port->uart.lock, flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -945,6 +967,7 @@ static int mn10300_serial_startup(struct uart_port *_port)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
port->rx_inp = port->rx_outp = 0;
|
|
|
|
|
port->tx_flags = 0;
|
|
|
|
|
|
|
|
|
|
/* finally, enable the device */
|
|
|
|
|
*port->_intr = SC01ICR_TI;
|
|
|
|
@@ -994,14 +1017,22 @@ error:
|
|
|
|
|
*/
|
|
|
|
|
static void mn10300_serial_shutdown(struct uart_port *_port)
|
|
|
|
|
{
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
u16 x;
|
|
|
|
|
struct mn10300_serial_port *port =
|
|
|
|
|
container_of(_port, struct mn10300_serial_port, uart);
|
|
|
|
|
|
|
|
|
|
_enter("%s", port->name);
|
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&_port->lock, flags);
|
|
|
|
|
mn10300_serial_dis_tx_intr(port);
|
|
|
|
|
|
|
|
|
|
*port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
|
|
|
|
|
x = *port->rx_icr;
|
|
|
|
|
port->tx_flags = 0;
|
|
|
|
|
spin_unlock_irqrestore(&_port->lock, flags);
|
|
|
|
|
|
|
|
|
|
/* disable the serial port and its baud rate timer */
|
|
|
|
|
port->tx_break = 0;
|
|
|
|
|
*port->_control &= ~(SC01CTR_TXE | SC01CTR_RXE | SC01CTR_BKE);
|
|
|
|
|
*port->_tmxmd = 0;
|
|
|
|
|
|
|
|
|
@@ -1016,12 +1047,8 @@ static void mn10300_serial_shutdown(struct uart_port *_port)
|
|
|
|
|
free_irq(port->rx_irq, port);
|
|
|
|
|
free_irq(port->tx_irq, port);
|
|
|
|
|
|
|
|
|
|
arch_local_cli();
|
|
|
|
|
*port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
|
|
|
|
|
x = *port->rx_icr;
|
|
|
|
|
*port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
|
|
|
|
|
x = *port->tx_icr;
|
|
|
|
|
arch_local_sti();
|
|
|
|
|
mn10300_serial_int_tbl[port->tx_irq].port = NULL;
|
|
|
|
|
mn10300_serial_int_tbl[port->rx_irq].port = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -1549,17 +1576,24 @@ static void mn10300_serial_console_write(struct console *co,
|
|
|
|
|
{
|
|
|
|
|
struct mn10300_serial_port *port;
|
|
|
|
|
unsigned i;
|
|
|
|
|
u16 scxctr, txicr, tmp;
|
|
|
|
|
u16 scxctr;
|
|
|
|
|
u8 tmxmd;
|
|
|
|
|
unsigned long flags;
|
|
|
|
|
int locked = 1;
|
|
|
|
|
|
|
|
|
|
port = mn10300_serial_ports[co->index];
|
|
|
|
|
|
|
|
|
|
local_irq_save(flags);
|
|
|
|
|
if (port->uart.sysrq) {
|
|
|
|
|
/* mn10300_serial_interrupt() already took the lock */
|
|
|
|
|
locked = 0;
|
|
|
|
|
} else if (oops_in_progress) {
|
|
|
|
|
locked = spin_trylock(&port->uart.lock);
|
|
|
|
|
} else
|
|
|
|
|
spin_lock(&port->uart.lock);
|
|
|
|
|
|
|
|
|
|
/* firstly hijack the serial port from the "virtual DMA" controller */
|
|
|
|
|
arch_local_cli();
|
|
|
|
|
txicr = *port->tx_icr;
|
|
|
|
|
*port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
|
|
|
|
|
tmp = *port->tx_icr;
|
|
|
|
|
arch_local_sti();
|
|
|
|
|
mn10300_serial_dis_tx_intr(port);
|
|
|
|
|
|
|
|
|
|
/* the transmitter may be disabled */
|
|
|
|
|
scxctr = *port->_control;
|
|
|
|
@@ -1613,10 +1647,11 @@ static void mn10300_serial_console_write(struct console *co,
|
|
|
|
|
if (!(scxctr & SC01CTR_TXE))
|
|
|
|
|
*port->_control = scxctr;
|
|
|
|
|
|
|
|
|
|
arch_local_cli();
|
|
|
|
|
*port->tx_icr = txicr;
|
|
|
|
|
tmp = *port->tx_icr;
|
|
|
|
|
arch_local_sti();
|
|
|
|
|
mn10300_serial_en_tx_intr(port);
|
|
|
|
|
|
|
|
|
|
if (locked)
|
|
|
|
|
spin_unlock(&port->uart.lock);
|
|
|
|
|
local_irq_restore(flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|