Commit d07e43d7 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'omap-serial' of git://git.linaro.org/people/rmk/linux-arm

Pull ARM OMAP serial updates from Russell King:
 "This series is a major reworking of the OMAP serial driver code fixing
  various bugs in the hardware-assisted flow control, extending up into
  serial_core for a couple of issues.  These fixes have been done as a
  set of progressive changes and transformations in the hope that no new
  bugs will be introduced by this series.

  The problems are many-fold, from the driver not being informed about
  updated settings, to the driver not knowing what the intentions of the
  upper layers are.

  The first four patches tackle the serial_core layer, allowing it to
  provide the necessary information to drivers, and the remaining
  patches allow the OMAP serial driver to take advantage of this.

  This brings hardware assisted RTS/CTS and XON/OFF flow control into a
  useful state.

  These patches have been in linux-next for most of the last cycle;
  indeed they predate the previous merge window.  They've also been
  posted to the OMAP people."

* 'omap-serial' of git://git.linaro.org/people/rmk/linux-arm: (21 commits)
  SERIAL: omap: fix hardware assisted flow control
  SERIAL: omap: simplify (2)
  SERIAL: omap: move xon/xoff setting earlier
  SERIAL: omap: always set TCR
  SERIAL: omap: simplify
  SERIAL: omap: don't read back LCR/MCR/EFR
  SERIAL: omap: serial_omap_configure_xonxoff() contents into set_termios
  SERIAL: omap: configure xon/xoff before setting modem control lines
  SERIAL: omap: remove OMAP_UART_SYSC_RESET and OMAP_UART_FIFO_CLR
  SERIAL: omap: move driver private definitions and structures to driver
  SERIAL: omap: remove 'irq_pending' bitfield
  SERIAL: omap: fix MCR TCRTLR bit handling
  SERIAL: omap: fix set_mctrl() breakage
  SERIAL: omap: no need to re-read EFR
  SERIAL: omap: remove setting of EFR SCD bit
  SERIAL: omap: allow hardware assisted IXANY mode to be disabled
  SERIAL: omap: allow hardware assisted rts/cts modes to be disabled
  SERIAL: core: add throttle/unthrottle callbacks for hardware assisted flow control
  SERIAL: core: add hardware assisted h/w flow control support
  SERIAL: core: add hardware assisted s/w flow control support
  ...

Conflicts:
	drivers/tty/serial/omap-serial.c
parents 1ebaf4f4 3af08bd7
......@@ -30,35 +30,6 @@
*/
#define OMAP_SERIAL_NAME "ttyO"
#define OMAP_MODE13X_SPEED 230400
#define OMAP_UART_SCR_TX_EMPTY 0x08
/* WER = 0x7F
* Enable module level wakeup in WER reg
*/
#define OMAP_UART_WER_MOD_WKUP 0X7F
/* Enable XON/XOFF flow control on output */
#define OMAP_UART_SW_TX 0x04
/* Enable XON/XOFF flow control on input */
#define OMAP_UART_SW_RX 0x04
#define OMAP_UART_SYSC_RESET 0X07
#define OMAP_UART_TCR_TRIG 0X0F
#define OMAP_UART_SW_CLR 0XF0
#define OMAP_UART_FIFO_CLR 0X06
#define OMAP_UART_DMA_CH_FREE -1
#define OMAP_MAX_HSUART_PORTS 6
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
#define UART_ERRATA_i202_MDR1_ACCESS BIT(0)
#define UART_ERRATA_i291_DMA_FORCEIDLE BIT(1)
struct omap_uart_port_info {
bool dma_enabled; /* To specify DMA Mode */
unsigned int uartclk; /* UART clock rate */
......@@ -77,30 +48,4 @@ struct omap_uart_port_info {
void (*enable_wakeup)(struct device *, bool);
};
struct uart_omap_dma {
u8 uart_dma_tx;
u8 uart_dma_rx;
int rx_dma_channel;
int tx_dma_channel;
dma_addr_t rx_buf_dma_phys;
dma_addr_t tx_buf_dma_phys;
unsigned int uart_base;
/*
* Buffer for rx dma.It is not required for tx because the buffer
* comes from port structure.
*/
unsigned char *rx_buf;
unsigned int prev_rx_dma_pos;
int tx_buf_size;
int tx_dma_used;
int rx_dma_used;
spinlock_t tx_lock;
spinlock_t rx_lock;
/* timer to poll activity on rx dma */
struct timer_list rx_timer;
unsigned int rx_buf_size;
unsigned int rx_poll_rate;
unsigned int rx_timeout;
};
#endif /* __OMAP_SERIAL_H__ */
This diff is collapsed.
......@@ -610,27 +610,50 @@ static void uart_send_xchar(struct tty_struct *tty, char ch)
static void uart_throttle(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
uint32_t mask = 0;
if (I_IXOFF(tty))
mask |= UPF_SOFT_FLOW;
if (tty->termios.c_cflag & CRTSCTS)
mask |= UPF_HARD_FLOW;
if (port->flags & mask) {
port->ops->throttle(port);
mask &= ~port->flags;
}
if (mask & UPF_SOFT_FLOW)
uart_send_xchar(tty, STOP_CHAR(tty));
if (tty->termios.c_cflag & CRTSCTS)
uart_clear_mctrl(state->uart_port, TIOCM_RTS);
if (mask & UPF_HARD_FLOW)
uart_clear_mctrl(port, TIOCM_RTS);
}
static void uart_unthrottle(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
uint32_t mask = 0;
if (I_IXOFF(tty)) {
if (I_IXOFF(tty))
mask |= UPF_SOFT_FLOW;
if (tty->termios.c_cflag & CRTSCTS)
mask |= UPF_HARD_FLOW;
if (port->flags & mask) {
port->ops->unthrottle(port);
mask &= ~port->flags;
}
if (mask & UPF_SOFT_FLOW) {
if (port->x_char)
port->x_char = 0;
else
uart_send_xchar(tty, START_CHAR(tty));
}
if (tty->termios.c_cflag & CRTSCTS)
if (mask & UPF_HARD_FLOW)
uart_set_mctrl(port, TIOCM_RTS);
}
......@@ -1214,9 +1237,22 @@ static void uart_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct uart_state *state = tty->driver_data;
struct uart_port *uport = state->uart_port;
unsigned long flags;
unsigned int cflag = tty->termios.c_cflag;
unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK;
bool sw_changed = false;
/*
* Drivers doing software flow control also need to know
* about changes to these input settings.
*/
if (uport->flags & UPF_SOFT_FLOW) {
iflag_mask |= IXANY|IXON|IXOFF;
sw_changed =
tty->termios.c_cc[VSTART] != old_termios->c_cc[VSTART] ||
tty->termios.c_cc[VSTOP] != old_termios->c_cc[VSTOP];
}
/*
* These are the bits that are used to setup various
......@@ -1224,11 +1260,11 @@ static void uart_set_termios(struct tty_struct *tty,
* bits in c_cflag; c_[io]speed will always be set
* appropriately by set_termios() in tty_ioctl.c
*/
#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
if ((cflag ^ old_termios->c_cflag) == 0 &&
tty->termios.c_ospeed == old_termios->c_ospeed &&
tty->termios.c_ispeed == old_termios->c_ispeed &&
RELEVANT_IFLAG(tty->termios.c_iflag ^ old_termios->c_iflag) == 0) {
((tty->termios.c_iflag ^ old_termios->c_iflag) & iflag_mask) == 0 &&
!sw_changed) {
return;
}
......@@ -1236,31 +1272,38 @@ static void uart_set_termios(struct tty_struct *tty,
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
uart_clear_mctrl(state->uart_port, TIOCM_RTS | TIOCM_DTR);
uart_clear_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
/* Handle transition away from B0 status */
else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
unsigned int mask = TIOCM_DTR;
if (!(cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags))
mask |= TIOCM_RTS;
uart_set_mctrl(state->uart_port, mask);
uart_set_mctrl(uport, mask);
}
/*
* If the port is doing h/w assisted flow control, do nothing.
* We assume that tty->hw_stopped has never been set.
*/
if (uport->flags & UPF_HARD_FLOW)
return;
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
spin_lock_irqsave(&state->uart_port->lock, flags);
spin_lock_irqsave(&uport->lock, flags);
tty->hw_stopped = 0;
__uart_start(tty);
spin_unlock_irqrestore(&state->uart_port->lock, flags);
spin_unlock_irqrestore(&uport->lock, flags);
}
/* Handle turning on CRTSCTS */
else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
spin_lock_irqsave(&state->uart_port->lock, flags);
if (!(state->uart_port->ops->get_mctrl(state->uart_port) & TIOCM_CTS)) {
spin_lock_irqsave(&uport->lock, flags);
if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) {
tty->hw_stopped = 1;
state->uart_port->ops->stop_tx(state->uart_port);
uport->ops->stop_tx(uport);
}
spin_unlock_irqrestore(&state->uart_port->lock, flags);
spin_unlock_irqrestore(&uport->lock, flags);
}
}
......
......@@ -46,6 +46,8 @@ struct uart_ops {
unsigned int (*get_mctrl)(struct uart_port *);
void (*stop_tx)(struct uart_port *);
void (*start_tx)(struct uart_port *);
void (*throttle)(struct uart_port *);
void (*unthrottle)(struct uart_port *);
void (*send_xchar)(struct uart_port *, char ch);
void (*stop_rx)(struct uart_port *);
void (*enable_ms)(struct uart_port *);
......@@ -163,6 +165,10 @@ struct uart_port {
#define UPF_BUGGY_UART ((__force upf_t) (1 << 14))
#define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15))
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16))
/* Port has hardware-assisted h/w flow control (iow, auto-RTS *not* auto-CTS) */
#define UPF_HARD_FLOW ((__force upf_t) (1 << 21))
/* Port has hardware-assisted s/w flow control */
#define UPF_SOFT_FLOW ((__force upf_t) (1 << 22))
#define UPF_CONS_FLOW ((__force upf_t) (1 << 23))
#define UPF_SHARE_IRQ ((__force upf_t) (1 << 24))
#define UPF_EXAR_EFR ((__force upf_t) (1 << 25))
......
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