Commit 8412ba1d authored by Julien Masson's avatar Julien Masson Committed by Greg Kroah-Hartman
Browse files

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: default avatarJulien Masson <jmasson@baylibre.com>
Link: https://lore.kernel.org/r/867e1klo48.fsf@julienm-fedora-R90NQGV9.i-did-not-set--mail-host-address--so-tickle-me


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 101aa46b
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of.h>
@@ -72,6 +73,8 @@
#define AML_UART_PORT_OFFSET		6
#define AML_UART_DEV_NAME		"ttyAML"

#define AML_UART_POLL_USEC		5
#define AML_UART_TIMEOUT_USEC		10000

static struct uart_driver meson_uart_driver;

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

#ifdef CONFIG_CONSOLE_POLL
/*
 * Console polling routines for writing and reading from the uart while
 * in an interrupt or debug context (i.e. kgdb).
 */

static int meson_uart_poll_get_char(struct uart_port *port)
{
	u32 c;
	unsigned long flags;

	spin_lock_irqsave(&port->lock, flags);

	if (readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY)
		c = NO_POLL_CHAR;
	else
		c = readl(port->membase + AML_UART_RFIFO);

	spin_unlock_irqrestore(&port->lock, flags);

	return c;
}

static void meson_uart_poll_put_char(struct uart_port *port, unsigned char c)
{
	unsigned long flags;
	u32 reg;
	int ret;

	spin_lock_irqsave(&port->lock, flags);

	/* Wait until FIFO is empty or timeout */
	ret = readl_poll_timeout_atomic(port->membase + AML_UART_STATUS, reg,
					reg & AML_UART_TX_EMPTY,
					AML_UART_POLL_USEC,
					AML_UART_TIMEOUT_USEC);
	if (ret == -ETIMEDOUT) {
		dev_err(port->dev, "Timeout waiting for UART TX EMPTY\n");
		goto out;
	}

	/* Write the character */
	writel(c, port->membase + AML_UART_WFIFO);

	/* Wait until FIFO is empty or timeout */
	ret = readl_poll_timeout_atomic(port->membase + AML_UART_STATUS, reg,
					reg & AML_UART_TX_EMPTY,
					AML_UART_POLL_USEC,
					AML_UART_TIMEOUT_USEC);
	if (ret == -ETIMEDOUT)
		dev_err(port->dev, "Timeout waiting for UART TX EMPTY\n");

out:
	spin_unlock_irqrestore(&port->lock, flags);
}

#endif /* CONFIG_CONSOLE_POLL */

static const struct uart_ops meson_uart_ops = {
	.set_mctrl      = meson_uart_set_mctrl,
	.get_mctrl      = meson_uart_get_mctrl,
@@ -438,6 +499,10 @@ static const struct uart_ops meson_uart_ops = {
	.request_port	= meson_uart_request_port,
	.release_port	= meson_uart_release_port,
	.verify_port	= meson_uart_verify_port,
#ifdef CONFIG_CONSOLE_POLL
	.poll_get_char	= meson_uart_poll_get_char,
	.poll_put_char	= meson_uart_poll_put_char,
#endif
};

#ifdef CONFIG_SERIAL_MESON_CONSOLE