Commit 0c0c47bc authored by Vlad Lungu's avatar Vlad Lungu Committed by Greg Kroah-Hartman

tty: xuartps: Implement BREAK detection, add SYSRQ support

The Cadence UART does not do break detection, even if the
datasheet says it does. This patch adds break detection in
software (tested in 8N1 mode only) and enables SYSRQ,
allowing for Break-g to enter KDB and all the other goodies.
Signed-off-by: default avatarVlad Lungu <vlad.lungu@windriver.com>
Signed-off-by: default avatarSoren Brinkmann <soren.brinkmann@xilinx.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c03cae17
......@@ -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) {
......
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