Skip to content

Commit 8412ba1

Browse files
massonjugregkh
authored andcommitted
tty: serial: meson_uart: Add support for kernel debugger
The kgdb invokes the poll_put_char and poll_get_char when communicating with the host. This patch implement the serial polling hooks for the meson_uart to be used for KGDB debugging over serial line. Signed-off-by: Julien Masson <[email protected]> Link: https://lore.kernel.org/r/867e1klo48.fsf@julienm-fedora-R90NQGV9.i-did-not-set--mail-host-address--so-tickle-me Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 101aa46 commit 8412ba1

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

drivers/tty/serial/meson_uart.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/delay.h>
1111
#include <linux/init.h>
1212
#include <linux/io.h>
13+
#include <linux/iopoll.h>
1314
#include <linux/module.h>
1415
#include <linux/kernel.h>
1516
#include <linux/of.h>
@@ -72,6 +73,8 @@
7273
#define AML_UART_PORT_OFFSET 6
7374
#define AML_UART_DEV_NAME "ttyAML"
7475

76+
#define AML_UART_POLL_USEC 5
77+
#define AML_UART_TIMEOUT_USEC 10000
7578

7679
static struct uart_driver meson_uart_driver;
7780

@@ -423,6 +426,64 @@ static void meson_uart_config_port(struct uart_port *port, int flags)
423426
}
424427
}
425428

429+
#ifdef CONFIG_CONSOLE_POLL
430+
/*
431+
* Console polling routines for writing and reading from the uart while
432+
* in an interrupt or debug context (i.e. kgdb).
433+
*/
434+
435+
static int meson_uart_poll_get_char(struct uart_port *port)
436+
{
437+
u32 c;
438+
unsigned long flags;
439+
440+
spin_lock_irqsave(&port->lock, flags);
441+
442+
if (readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY)
443+
c = NO_POLL_CHAR;
444+
else
445+
c = readl(port->membase + AML_UART_RFIFO);
446+
447+
spin_unlock_irqrestore(&port->lock, flags);
448+
449+
return c;
450+
}
451+
452+
static void meson_uart_poll_put_char(struct uart_port *port, unsigned char c)
453+
{
454+
unsigned long flags;
455+
u32 reg;
456+
int ret;
457+
458+
spin_lock_irqsave(&port->lock, flags);
459+
460+
/* Wait until FIFO is empty or timeout */
461+
ret = readl_poll_timeout_atomic(port->membase + AML_UART_STATUS, reg,
462+
reg & AML_UART_TX_EMPTY,
463+
AML_UART_POLL_USEC,
464+
AML_UART_TIMEOUT_USEC);
465+
if (ret == -ETIMEDOUT) {
466+
dev_err(port->dev, "Timeout waiting for UART TX EMPTY\n");
467+
goto out;
468+
}
469+
470+
/* Write the character */
471+
writel(c, port->membase + AML_UART_WFIFO);
472+
473+
/* Wait until FIFO is empty or timeout */
474+
ret = readl_poll_timeout_atomic(port->membase + AML_UART_STATUS, reg,
475+
reg & AML_UART_TX_EMPTY,
476+
AML_UART_POLL_USEC,
477+
AML_UART_TIMEOUT_USEC);
478+
if (ret == -ETIMEDOUT)
479+
dev_err(port->dev, "Timeout waiting for UART TX EMPTY\n");
480+
481+
out:
482+
spin_unlock_irqrestore(&port->lock, flags);
483+
}
484+
485+
#endif /* CONFIG_CONSOLE_POLL */
486+
426487
static const struct uart_ops meson_uart_ops = {
427488
.set_mctrl = meson_uart_set_mctrl,
428489
.get_mctrl = meson_uart_get_mctrl,
@@ -438,6 +499,10 @@ static const struct uart_ops meson_uart_ops = {
438499
.request_port = meson_uart_request_port,
439500
.release_port = meson_uart_release_port,
440501
.verify_port = meson_uart_verify_port,
502+
#ifdef CONFIG_CONSOLE_POLL
503+
.poll_get_char = meson_uart_poll_get_char,
504+
.poll_put_char = meson_uart_poll_put_char,
505+
#endif
441506
};
442507

443508
#ifdef CONFIG_SERIAL_MESON_CONSOLE

0 commit comments

Comments
 (0)