diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8efd7c2..05bfe9f 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -41,6 +41,10 @@
 #include <linux/sizes.h>
 #include <linux/io.h>
 #include <linux/acpi.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/irq_work.h>
+#include <linux/kfifo.h>
 
 #include "amba-pl011.h"
 
@@ -273,6 +277,12 @@ struct uart_amba_port {
 	struct pl011_dmatx_data	dmatx;
 	bool			dma_probed;
 #endif
+#ifdef CONFIG_CONSOLE_POLL
+	bool			poll_mode_active;
+	struct irq_work		nmi_work;
+	DECLARE_KFIFO(nmi_fifo, unsigned int, 256);
+	DECLARE_KFIFO(nmi_fifo_flag, unsigned int, 256);
+#endif
 };
 
 static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap,
@@ -347,6 +357,13 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
 		if (uart_handle_sysrq_char(&uap->port, ch & 255))
 			continue;
 
+#ifdef CONFIG_CONSOLE_POLL
+		if (in_nmi()) {
+			kfifo_in(&uap->nmi_fifo, &ch, 1);
+			kfifo_in(&uap->nmi_fifo_flag, &flag, 1);
+			continue;
+		}
+#endif
 		uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
 	}
 
@@ -1286,6 +1303,10 @@ static void pl011_stop_tx(struct uart_port *port)
 	struct uart_amba_port *uap =
 	    container_of(port, struct uart_amba_port, port);
 
+#ifdef CONFIG_CONSOLE_POLL
+	if (uap->poll_mode_active)
+		return;
+#endif
 	uap->im &= ~UART011_TXIM;
 	pl011_write(uap->im, uap, REG_IMSC);
 	pl011_dma_tx_stop(uap);
@@ -1302,11 +1323,21 @@ static void pl011_start_tx_pio(struct uart_amba_port *uap)
 	}
 }
 
+#ifdef CONFIG_CONSOLE_POLL
+static void pl011_poll_tx_chars(struct uart_amba_port *uap);
+#endif
+
 static void pl011_start_tx(struct uart_port *port)
 {
 	struct uart_amba_port *uap =
 	    container_of(port, struct uart_amba_port, port);
 
+#ifdef CONFIG_CONSOLE_POLL
+	if (uap->poll_mode_active) {
+		pl011_poll_tx_chars(uap);
+		return;
+	}
+#endif
 	if (!pl011_dma_tx_start(uap))
 		pl011_start_tx_pio(uap);
 }
@@ -1316,6 +1347,10 @@ static void pl011_stop_rx(struct uart_port *port)
 	struct uart_amba_port *uap =
 	    container_of(port, struct uart_amba_port, port);
 
+#ifdef CONFIG_CONSOLE_POLL
+	if (uap->poll_mode_active)
+		return;
+#endif
 	uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
 		     UART011_PEIM|UART011_BEIM|UART011_OEIM);
 	pl011_write(uap->im, uap, REG_IMSC);
@@ -1637,6 +1672,128 @@ static void pl011_put_poll_char(struct uart_port *port,
 	pl011_write(ch, uap, REG_DR);
 }
 
+static void pl011_poll_tx_chars(struct uart_amba_port *uap)
+{
+	struct circ_buf *xmit = &uap->port.state->xmit;
+
+	if (uap->port.x_char) {
+		pl011_put_poll_char(&uap->port, uap->port.x_char);
+		uap->port.x_char = 0;
+	}
+
+	while (!uart_circ_empty(xmit)) {
+		pl011_put_poll_char(&uap->port, xmit->buf[xmit->tail]);
+		uap->port.icount.tx++;
+
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+	}
+}
+
+static void pl011_nmi_tty_work(struct irq_work *nmi_work)
+{
+	struct uart_amba_port *uap =
+	    container_of(nmi_work, struct uart_amba_port, nmi_work);
+	unsigned int ch, flag;
+
+	if (!uap->port.state || !tty_port_active(&uap->port.state->port)) {
+		kfifo_reset(&uap->nmi_fifo);
+		kfifo_reset(&uap->nmi_fifo_flag);
+		return;
+	}
+
+	if (unlikely(!kfifo_len(&uap->nmi_fifo) ||
+		     !kfifo_len(&uap->nmi_fifo_flag)))
+		return;
+
+	spin_lock(&uap->port.lock);
+	while (kfifo_out(&uap->nmi_fifo, &ch, 1) &&
+	       kfifo_out(&uap->nmi_fifo_flag, &flag, 1))
+		uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
+	spin_unlock(&uap->port.lock);
+
+	tty_flip_buffer_push(&uap->port.state->port);
+}
+
+static void pl011_nmi_rx_chars(struct uart_amba_port *uap)
+{
+	pl011_fifo_to_tty(uap);
+	irq_work_queue(&uap->nmi_work);
+}
+
+static irqreturn_t pl011_nmi_int(int irq, void *dev_id)
+{
+	struct uart_amba_port *uap = dev_id;
+	unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
+	int handled = 0;
+
+	status = pl011_read(uap, REG_MIS);
+	if (status) {
+		do {
+			check_apply_cts_event_workaround(uap);
+
+			pl011_write(status, uap, REG_ICR);
+
+			if (status)
+				pl011_nmi_rx_chars(uap);
+
+			if (pass_counter-- == 0)
+				break;
+
+			status = pl011_read(uap, REG_MIS);
+		} while (status != 0);
+		handled = 1;
+	}
+
+	return IRQ_RETVAL(handled);
+}
+
+static int pl011_allocate_nmi(struct uart_amba_port *uap)
+{
+	int ret;
+
+	irq_set_status_flags(uap->port.irq, IRQ_NOAUTOEN);
+	ret = request_nmi(uap->port.irq, pl011_nmi_int, IRQF_PERCPU,
+			  "uart-pl011", uap);
+	if (ret) {
+		irq_clear_status_flags(uap->port.irq, IRQ_NOAUTOEN);
+		return ret;
+	}
+
+	enable_irq(uap->port.irq);
+
+	return ret;
+}
+
+static int pl011_hwinit(struct uart_port *port);
+
+static int pl011_poll_init(struct uart_port *port)
+{
+	struct uart_amba_port *uap =
+	    container_of(port, struct uart_amba_port, port);
+	int retval;
+
+	retval = pl011_hwinit(port);
+	if (retval)
+		goto clk_dis;
+
+	/* In case NMI isn't supported, fallback to normal interrupt mode */
+	retval = pl011_allocate_nmi(uap);
+	if (retval)
+		return 0;
+
+	INIT_KFIFO(uap->nmi_fifo);
+	INIT_KFIFO(uap->nmi_fifo_flag);
+	init_irq_work(&uap->nmi_work, pl011_nmi_tty_work);
+
+	uap->poll_mode_active = true;
+
+	return 0;
+
+ clk_dis:
+	clk_disable_unprepare(uap->clk);
+	return retval;
+}
+
 #endif /* CONFIG_CONSOLE_POLL */
 
 static int pl011_hwinit(struct uart_port *port)
@@ -1748,6 +1905,10 @@ static int pl011_startup(struct uart_port *port)
 	unsigned int cr;
 	int retval;
 
+#ifdef CONFIG_CONSOLE_POLL
+	if (uap->poll_mode_active)
+		return 0;
+#endif
 	retval = pl011_hwinit(port);
 	if (retval)
 		goto clk_dis;
@@ -1790,6 +1951,10 @@ static int sbsa_uart_startup(struct uart_port *port)
 		container_of(port, struct uart_amba_port, port);
 	int retval;
 
+#ifdef CONFIG_CONSOLE_POLL
+	if (uap->poll_mode_active)
+		return 0;
+#endif
 	retval = pl011_hwinit(port);
 	if (retval)
 		return retval;
@@ -1859,6 +2024,10 @@ static void pl011_shutdown(struct uart_port *port)
 	struct uart_amba_port *uap =
 		container_of(port, struct uart_amba_port, port);
 
+#ifdef CONFIG_CONSOLE_POLL
+	if (uap->poll_mode_active)
+		return;
+#endif
 	pl011_disable_interrupts(uap);
 
 	pl011_dma_shutdown(uap);
@@ -1891,6 +2060,10 @@ static void sbsa_uart_shutdown(struct uart_port *port)
 	struct uart_amba_port *uap =
 		container_of(port, struct uart_amba_port, port);
 
+#ifdef CONFIG_CONSOLE_POLL
+	if (uap->poll_mode_active)
+		return;
+#endif
 	pl011_disable_interrupts(uap);
 
 	free_irq(uap->port.irq, uap);
@@ -2142,7 +2315,7 @@ static const struct uart_ops amba_pl011_pops = {
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_init     = pl011_hwinit,
+	.poll_init     = pl011_poll_init,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
@@ -2173,7 +2346,7 @@ static const struct uart_ops sbsa_uart_pops = {
 	.config_port	= pl011_config_port,
 	.verify_port	= pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-	.poll_init     = pl011_hwinit,
+	.poll_init     = pl011_poll_init,
 	.poll_get_char = pl011_get_poll_char,
 	.poll_put_char = pl011_put_poll_char,
 #endif
