Skip to content

Commit 0c0c47b

Browse files
vllungugregkh
authored andcommitted
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: Vlad Lungu <vlad.lungu@windriver.com> Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent c03cae1 commit 0c0c47b

File tree

1 file changed

+49
-1
lines changed

1 file changed

+49
-1
lines changed

drivers/tty/serial/xilinx_uartps.c

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,17 @@
1111
*
1212
*/
1313

14+
#if defined(CONFIG_SERIAL_XILINX_PS_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
15+
#define SUPPORT_SYSRQ
16+
#endif
17+
1418
#include <linux/platform_device.h>
1519
#include <linux/serial.h>
20+
#include <linux/console.h>
1621
#include <linux/serial_core.h>
1722
#include <linux/slab.h>
1823
#include <linux/tty.h>
1924
#include <linux/tty_flip.h>
20-
#include <linux/console.h>
2125
#include <linux/clk.h>
2226
#include <linux/irq.h>
2327
#include <linux/io.h>
@@ -128,6 +132,9 @@
128132
#define XUARTPS_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
129133
#define XUARTPS_IXR_MASK 0x00001FFF /* Valid bit mask */
130134

135+
/* Goes in read_status_mask for break detection as the HW doesn't do it*/
136+
#define XUARTPS_IXR_BRK 0x80000000
137+
131138
/** Channel Status Register
132139
*
133140
* 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)
171178
*/
172179
isrstatus = xuartps_readl(XUARTPS_ISR_OFFSET);
173180

181+
/*
182+
* There is no hardware break detection, so we interpret framing
183+
* error with all-zeros data as a break sequence. Most of the time,
184+
* there's another non-zero byte at the end of the sequence.
185+
*/
186+
187+
if (isrstatus & XUARTPS_IXR_FRAMING) {
188+
while (!(xuartps_readl(XUARTPS_SR_OFFSET) &
189+
XUARTPS_SR_RXEMPTY)) {
190+
if (!xuartps_readl(XUARTPS_FIFO_OFFSET)) {
191+
port->read_status_mask |= XUARTPS_IXR_BRK;
192+
isrstatus &= ~XUARTPS_IXR_FRAMING;
193+
}
194+
}
195+
xuartps_writel(XUARTPS_IXR_FRAMING, XUARTPS_ISR_OFFSET);
196+
}
197+
174198
/* drop byte with parity error if IGNPAR specified */
175199
if (isrstatus & port->ignore_status_mask & XUARTPS_IXR_PARITY)
176200
isrstatus &= ~(XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT);
@@ -184,6 +208,30 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)
184208
while ((xuartps_readl(XUARTPS_SR_OFFSET) &
185209
XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) {
186210
data = xuartps_readl(XUARTPS_FIFO_OFFSET);
211+
212+
/* Non-NULL byte after BREAK is garbage (99%) */
213+
if (data && (port->read_status_mask &
214+
XUARTPS_IXR_BRK)) {
215+
port->read_status_mask &= ~XUARTPS_IXR_BRK;
216+
port->icount.brk++;
217+
if (uart_handle_break(port))
218+
continue;
219+
}
220+
221+
/*
222+
* uart_handle_sysrq_char() doesn't work if
223+
* spinlocked, for some reason
224+
*/
225+
if (port->sysrq) {
226+
spin_unlock(&port->lock);
227+
if (uart_handle_sysrq_char(port,
228+
(unsigned char)data)) {
229+
spin_lock(&port->lock);
230+
continue;
231+
}
232+
spin_lock(&port->lock);
233+
}
234+
187235
port->icount.rx++;
188236

189237
if (isrstatus & XUARTPS_IXR_PARITY) {

0 commit comments

Comments
 (0)