aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial
diff options
context:
space:
mode:
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>2018-03-02 11:07:20 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-03-09 10:21:01 -0800
commit3a0ab62f43de5c6ec55fb9d6721168602008142a (patch)
treec57e3c5448196442e1b6c61e1728f71505183126 /drivers/tty/serial
parentserial: imx: add wrappers for writel and readl (diff)
downloadlinux-dev-3a0ab62f43de5c6ec55fb9d6721168602008142a.tar.xz
linux-dev-3a0ab62f43de5c6ec55fb9d6721168602008142a.zip
serial: imx: implement shadow registers for UCRx and UFCR
This reduces the amount of read accesses to the register space by shadowing the values for five registers that only change on writing them. There is a single bit in UCR2 that might change without being written to it, this is handled accordingly. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial')
-rw-r--r--drivers/tty/serial/imx.c60
1 files changed, 59 insertions, 1 deletions
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 659a949bed8a..57891d21f20d 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -204,6 +204,13 @@ struct imx_port {
struct mctrl_gpios *gpios;
+ /* shadow registers */
+ unsigned int ucr1;
+ unsigned int ucr2;
+ unsigned int ucr3;
+ unsigned int ucr4;
+ unsigned int ufcr;
+
/* DMA fields */
unsigned int dma_is_enabled:1;
unsigned int dma_is_rxing:1;
@@ -275,12 +282,56 @@ MODULE_DEVICE_TABLE(of, imx_uart_dt_ids);
static void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset)
{
+ switch (offset) {
+ case UCR1:
+ sport->ucr1 = val;
+ break;
+ case UCR2:
+ sport->ucr2 = val;
+ break;
+ case UCR3:
+ sport->ucr3 = val;
+ break;
+ case UCR4:
+ sport->ucr4 = val;
+ break;
+ case UFCR:
+ sport->ufcr = val;
+ break;
+ default:
+ break;
+ }
writel(val, sport->port.membase + offset);
}
static u32 imx_uart_readl(struct imx_port *sport, u32 offset)
{
- return readl(sport->port.membase + offset);
+ switch (offset) {
+ case UCR1:
+ return sport->ucr1;
+ break;
+ case UCR2:
+ /*
+ * UCR2_SRST is the only bit in the cached registers that might
+ * differ from the value that was last written. As it only
+ * clears after being set, reread conditionally.
+ */
+ if (sport->ucr2 & UCR2_SRST)
+ sport->ucr2 = readl(sport->port.membase + offset);
+ return sport->ucr2;
+ break;
+ case UCR3:
+ return sport->ucr3;
+ break;
+ case UCR4:
+ return sport->ucr4;
+ break;
+ case UFCR:
+ return sport->ufcr;
+ break;
+ default:
+ return readl(sport->port.membase + offset);
+ }
}
static inline unsigned uts_reg(struct imx_port *sport)
@@ -2136,6 +2187,13 @@ static int serial_imx_probe(struct platform_device *pdev)
return ret;
}
+ /* initialize shadow register values */
+ sport->ucr1 = readl(sport->port.membase + UCR1);
+ sport->ucr2 = readl(sport->port.membase + UCR2);
+ sport->ucr3 = readl(sport->port.membase + UCR3);
+ sport->ucr4 = readl(sport->port.membase + UCR4);
+ sport->ufcr = readl(sport->port.membase + UFCR);
+
uart_get_rs485_mode(&pdev->dev, &sport->port.rs485);
if (sport->port.rs485.flags & SER_RS485_ENABLED &&