diff options
-rw-r--r-- | drivers/tty/serial/xilinx_uartps.c | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 8c0745951605..5d5557af4d22 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -11,13 +11,17 @@ * */ +#if defined(CONFIG_SERIAL_XILINX_PS_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + #include <linux/platform_device.h> #include <linux/serial.h> +#include <linux/console.h> #include <linux/serial_core.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_flip.h> -#include <linux/console.h> #include <linux/clk.h> #include <linux/irq.h> #include <linux/io.h> @@ -128,6 +132,9 @@ #define XUARTPS_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */ #define XUARTPS_IXR_MASK 0x00001FFF /* Valid bit mask */ +/* Goes in read_status_mask for break detection as the HW doesn't do it*/ +#define XUARTPS_IXR_BRK 0x80000000 + /** Channel Status Register * * The channel status register (CSR) is provided to enable the control logic @@ -171,6 +178,23 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) */ isrstatus = xuartps_readl(XUARTPS_ISR_OFFSET); + /* + * There is no hardware break detection, so we interpret framing + * error with all-zeros data as a break sequence. Most of the time, + * there's another non-zero byte at the end of the sequence. + */ + + if (isrstatus & XUARTPS_IXR_FRAMING) { + while (!(xuartps_readl(XUARTPS_SR_OFFSET) & + XUARTPS_SR_RXEMPTY)) { + if (!xuartps_readl(XUARTPS_FIFO_OFFSET)) { + port->read_status_mask |= XUARTPS_IXR_BRK; + isrstatus &= ~XUARTPS_IXR_FRAMING; + } + } + xuartps_writel(XUARTPS_IXR_FRAMING, XUARTPS_ISR_OFFSET); + } + /* drop byte with parity error if IGNPAR specified */ if (isrstatus & port->ignore_status_mask & XUARTPS_IXR_PARITY) isrstatus &= ~(XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT); @@ -184,6 +208,30 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) while ((xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) { data = xuartps_readl(XUARTPS_FIFO_OFFSET); + + /* Non-NULL byte after BREAK is garbage (99%) */ + if (data && (port->read_status_mask & + XUARTPS_IXR_BRK)) { + port->read_status_mask &= ~XUARTPS_IXR_BRK; + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } + + /* + * uart_handle_sysrq_char() doesn't work if + * spinlocked, for some reason + */ + if (port->sysrq) { + spin_unlock(&port->lock); + if (uart_handle_sysrq_char(port, + (unsigned char)data)) { + spin_lock(&port->lock); + continue; + } + spin_lock(&port->lock); + } + port->icount.rx++; if (isrstatus & XUARTPS_IXR_PARITY) { |