From: Dave Martin <Dave.Martin@arm.com>
To: linux-arm-kernel@lists.infradead.org
Cc: Andre Przywara <andre.przywara@arm.com>,
Stephen Boyd <sboyd@codeaurora.org>,
Russell King <linux@armlinux.org.uk>,
Andy Gross <andy.gross@linaro.org>,
linux-serial@vger.kernel.org,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Bhupinder Thakur <bhupinder.thakur@linaro.org>
Subject: [RFC PATCH 1/3] tty: amba-pl011: earlycon: Switch to relaxed I/O
Date: Wed, 18 Oct 2017 15:14:46 +0100 [thread overview]
Message-ID: <1508336088-3948-2-git-send-email-Dave.Martin@arm.com> (raw)
In-Reply-To: <1508336088-3948-1-git-send-email-Dave.Martin@arm.com>
The current pl011 earlycon implementation uses the regular I/O
accessors, but this is unnecessary because the architecture
enforces ordering of accesses to the same device anyway.
Using relaxed I/O brings the added bonus that the generic pl011
helpers can be used instead of having to open-code: this allows
some duplicate logic to be unified.
This patch does some refactoring so that pl011_{read,write,
tx_empty}() are split into a frontend that does the same thing as
before, and a backend __* that can be used with a uart_port that
has no corresponding uart_amba_port structure yet (i.e., the
earlycon scenario).
__pl011_tx_empty() can now be used in place of an open-coded poll
that differs between the generic and qdf2400_e44 earlycon
implementations, because __pl011_tx_empty() handles the necessary
quirkage transparently.
Moving to relaxed I/O loses wmb() semantics at the start of an
earlycon write, and this may be important for some debugging
scenarios, so an explicit wmb() is inserted at the start of each
earlycon write implementation.
Because qdf2400_e44 only supports 32-bit I/O, this patch also
explicitly sets port->iotype == UPIO_MEM32 so that __pl011_{write,
read}() use the correct I/O size.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
drivers/tty/serial/amba-pl011.c | 69 ++++++++++++++++++++++++++++-------------
1 file changed, 47 insertions(+), 22 deletions(-)
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 111e6a9..fd9e08c 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -300,26 +300,38 @@ static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap,
return uap->reg_offset[reg];
}
-static unsigned int pl011_read(const struct uart_amba_port *uap,
- unsigned int reg)
+static unsigned int __pl011_read(const struct uart_port *port,
+ const u16 *reg_offset, unsigned int reg)
{
- void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg);
+ void __iomem *addr = port->membase + reg_offset[reg];
- return (uap->port.iotype == UPIO_MEM32) ?
+ return (port->iotype == UPIO_MEM32) ?
readl_relaxed(addr) : readw_relaxed(addr);
}
-static void pl011_write(unsigned int val, const struct uart_amba_port *uap,
+static unsigned int pl011_read(const struct uart_amba_port *uap,
unsigned int reg)
{
- void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg);
+ return __pl011_read(&uap->port, uap->reg_offset, reg);
+}
- if (uap->port.iotype == UPIO_MEM32)
+static void __pl011_write(unsigned int val, const struct uart_port *port,
+ const u16 *reg_offset, unsigned int reg)
+{
+ void __iomem *addr = port->membase + reg_offset[reg];
+
+ if (port->iotype == UPIO_MEM32)
writel_relaxed(val, addr);
else
writew_relaxed(val, addr);
}
+static void pl011_write(unsigned int val, const struct uart_amba_port *uap,
+ unsigned int reg)
+{
+ __pl011_write(val, &uap->port, uap->reg_offset, reg);
+}
+
/*
* Reads up to 256 characters from the FIFO or until it's empty and
* inserts them into the TTY layer. Returns the number of characters
@@ -1537,16 +1549,23 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
-static unsigned int pl011_tx_empty(struct uart_port *port)
+static unsigned int __pl011_tx_empty(struct uart_port *port,
+ const u16 *reg_offset, const struct vendor_data *vendor)
{
- struct uart_amba_port *uap =
- container_of(port, struct uart_amba_port, port);
+ unsigned int status = __pl011_read(port, reg_offset, REG_FR);
/* Allow feature register bits to be inverted to work around errata */
- unsigned int status = pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr;
+ status ^= vendor->inv_fr;
+ status &= vendor->fr_busy | UART01x_FR_TXFF;
+ return status ? 0 : TIOCSER_TEMT;
+}
- return status & (uap->vendor->fr_busy | UART01x_FR_TXFF) ?
- 0 : TIOCSER_TEMT;
+static unsigned int pl011_tx_empty(struct uart_port *port)
+{
+ struct uart_amba_port *uap =
+ container_of(port, struct uart_amba_port, port);
+
+ return __pl011_tx_empty(port, uap->reg_offset, uap->vendor);
}
static unsigned int pl011_get_mctrl(struct uart_port *port)
@@ -2419,10 +2438,13 @@ static struct console amba_console = {
static void qdf2400_e44_putc(struct uart_port *port, int c)
{
- while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
+ const struct vendor_data *vendor = &vendor_qdt_qdf2400_e44;
+ const u16 *reg_offset = vendor->reg_offset;
+
+ while (__pl011_read(port, reg_offset, REG_FR) & UART01x_FR_TXFF)
cpu_relax();
- writel(c, port->membase + UART01x_DR);
- while (!(readl(port->membase + UART01x_FR) & UART011_FR_TXFE))
+ __pl011_write(c, port, reg_offset, REG_DR);
+ while (!__pl011_tx_empty(port, reg_offset, vendor))
cpu_relax();
}
@@ -2430,18 +2452,19 @@ static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned
{
struct earlycon_device *dev = con->data;
+ wmb();
uart_console_write(&dev->port, s, n, qdf2400_e44_putc);
}
static void pl011_putc(struct uart_port *port, int c)
{
- while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
+ const struct vendor_data *vendor = &vendor_arm;
+ const u16 *reg_offset = vendor->reg_offset;
+
+ while (__pl011_read(port, reg_offset, REG_FR) & UART01x_FR_TXFF)
cpu_relax();
- if (port->iotype == UPIO_MEM32)
- writel(c, port->membase + UART01x_DR);
- else
- writeb(c, port->membase + UART01x_DR);
- while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
+ __pl011_write(c, port, reg_offset, REG_DR);
+ while (!__pl011_tx_empty(port, reg_offset, vendor))
cpu_relax();
}
@@ -2449,6 +2472,7 @@ static void pl011_early_write(struct console *con, const char *s, unsigned n)
{
struct earlycon_device *dev = con->data;
+ wmb();
uart_console_write(&dev->port, s, n, pl011_putc);
}
@@ -2494,6 +2518,7 @@ qdf2400_e44_early_console_setup(struct earlycon_device *device,
if (!device->port.membase)
return -ENODEV;
+ device->port.iotype = UPIO_MEM32;
device->con->write = qdf2400_e44_early_write;
return 0;
}
--
2.1.4
next prev parent reply other threads:[~2017-10-18 14:14 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-10-18 14:14 [RFC PATCH 0/3] tty: amba-pl011: Decruft and streamline earlycon output Dave Martin
2017-10-18 14:14 ` Dave Martin [this message]
2017-10-18 14:14 ` [RFC PATCH 2/3] tty: amba-pl011: earlycon: Unify earlycon backends Dave Martin
2017-10-18 14:14 ` [RFC PATCH 3/3] tty: amba-pl011: earlycon: Don't drain the transmitter after each char Dave Martin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1508336088-3948-2-git-send-email-Dave.Martin@arm.com \
--to=dave.martin@arm.com \
--cc=andre.przywara@arm.com \
--cc=andy.gross@linaro.org \
--cc=bhupinder.thakur@linaro.org \
--cc=gregkh@linuxfoundation.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-serial@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=sboyd@codeaurora.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).