From 3a0ab62f43de5c6ec55fb9d6721168602008142a Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 2 Mar 2018 11:07:20 +0100 Subject: serial: imx: implement shadow registers for UCRx and UFCR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) (limited to 'drivers/tty') 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 && -- cgit v1.2.3