aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/xilinx_uartps.c
diff options
context:
space:
mode:
authorVlad Lungu <vlad.lungu@windriver.com>2013-10-17 17:08:06 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-10-19 22:47:37 -0400
commit0c0c47bc40a2e358d593b2d7fb93b50027fbfc0c (patch)
tree1f38689bc64044ba087c7394079c7a62d81c81fa /drivers/tty/serial/xilinx_uartps.c
parentc03cae1791407f4f4f9bc6b0354ecaeb50df787f (diff)
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>
Diffstat (limited to 'drivers/tty/serial/xilinx_uartps.c')
-rw-r--r--drivers/tty/serial/xilinx_uartps.c50
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 @@
11 * 11 *
12 */ 12 */
13 13
14#if defined(CONFIG_SERIAL_XILINX_PS_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
15#define SUPPORT_SYSRQ
16#endif
17
14#include <linux/platform_device.h> 18#include <linux/platform_device.h>
15#include <linux/serial.h> 19#include <linux/serial.h>
20#include <linux/console.h>
16#include <linux/serial_core.h> 21#include <linux/serial_core.h>
17#include <linux/slab.h> 22#include <linux/slab.h>
18#include <linux/tty.h> 23#include <linux/tty.h>
19#include <linux/tty_flip.h> 24#include <linux/tty_flip.h>
20#include <linux/console.h>
21#include <linux/clk.h> 25#include <linux/clk.h>
22#include <linux/irq.h> 26#include <linux/irq.h>
23#include <linux/io.h> 27#include <linux/io.h>
@@ -128,6 +132,9 @@
128#define XUARTPS_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */ 132#define XUARTPS_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
129#define XUARTPS_IXR_MASK 0x00001FFF /* Valid bit mask */ 133#define XUARTPS_IXR_MASK 0x00001FFF /* Valid bit mask */
130 134
135/* Goes in read_status_mask for break detection as the HW doesn't do it*/
136#define XUARTPS_IXR_BRK 0x80000000
137
131/** Channel Status Register 138/** Channel Status Register
132 * 139 *
133 * The channel status register (CSR) is provided to enable the control logic 140 * 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)
171 */ 178 */
172 isrstatus = xuartps_readl(XUARTPS_ISR_OFFSET); 179 isrstatus = xuartps_readl(XUARTPS_ISR_OFFSET);
173 180
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
174 /* drop byte with parity error if IGNPAR specified */ 198 /* drop byte with parity error if IGNPAR specified */
175 if (isrstatus & port->ignore_status_mask & XUARTPS_IXR_PARITY) 199 if (isrstatus & port->ignore_status_mask & XUARTPS_IXR_PARITY)
176 isrstatus &= ~(XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT); 200 isrstatus &= ~(XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT);
@@ -184,6 +208,30 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id)
184 while ((xuartps_readl(XUARTPS_SR_OFFSET) & 208 while ((xuartps_readl(XUARTPS_SR_OFFSET) &
185 XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) { 209 XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) {
186 data = xuartps_readl(XUARTPS_FIFO_OFFSET); 210 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
187 port->icount.rx++; 235 port->icount.rx++;
188 236
189 if (isrstatus & XUARTPS_IXR_PARITY) { 237 if (isrstatus & XUARTPS_IXR_PARITY) {