linux-serial.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] tty/serial: atmel: ensure state is restored after suspending
@ 2017-02-03 22:53 Alexandre Belloni
  2017-02-06  9:31 ` Nicolas Ferre
  2017-02-06 11:10 ` Richard Genoud
  0 siblings, 2 replies; 3+ messages in thread
From: Alexandre Belloni @ 2017-02-03 22:53 UTC (permalink / raw)
  To: Richard Genoud
  Cc: Greg Kroah-Hartman, Nicolas Ferre, linux-arm-kernel, linux-serial,
	linux-kernel, Alexandre Belloni

When going to suspend, the UART registers may be lost because the power to
VDDcore is cut. This is not an issue in the normal case but when
no_console_suspend is used, we need to restore the registers in order to
get a functional console.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
 drivers/tty/serial/atmel_serial.c | 44 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 168b10cad47b..22e0a73c0cb7 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -175,6 +175,17 @@ struct atmel_uart_port {
 	unsigned int		pending_status;
 	spinlock_t		lock_suspended;
 
+	struct {
+		u32		cr;
+		u32		mr;
+		u32		imr;
+		u32		brgr;
+		u32		rtor;
+		u32		ttgr;
+		u32		fmr;
+		u32		fimr;
+	} cache;
+
 	int (*prepare_rx)(struct uart_port *port);
 	int (*prepare_tx)(struct uart_port *port);
 	void (*schedule_rx)(struct uart_port *port);
@@ -2649,6 +2660,20 @@ static int atmel_serial_suspend(struct platform_device *pdev,
 			cpu_relax();
 	}
 
+	if (atmel_is_console_port(port) && !console_suspend_enabled) {
+		/* Cache register values as we won't get a full shutdown/startup
+		 * cycle
+		 */
+		atmel_port->cache.mr = atmel_uart_readl(port, ATMEL_US_MR);
+		atmel_port->cache.imr = atmel_uart_readl(port, ATMEL_US_IMR);
+		atmel_port->cache.brgr = atmel_uart_readl(port, ATMEL_US_BRGR);
+		atmel_port->cache.rtor = atmel_uart_readl(port,
+							  atmel_port->rtor);
+		atmel_port->cache.ttgr = atmel_uart_readl(port, ATMEL_US_TTGR);
+		atmel_port->cache.fmr = atmel_uart_readl(port, ATMEL_US_FMR);
+		atmel_port->cache.fimr = atmel_uart_readl(port, ATMEL_US_FIMR);
+	}
+
 	/* we can not wake up if we're running on slow clock */
 	atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
 	if (atmel_serial_clk_will_stop()) {
@@ -2671,6 +2696,25 @@ static int atmel_serial_resume(struct platform_device *pdev)
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 	unsigned long flags;
 
+	if (atmel_is_console_port(port) && !console_suspend_enabled) {
+		atmel_uart_writel(port, ATMEL_US_MR, atmel_port->cache.mr);
+		atmel_uart_writel(port, ATMEL_US_IER, atmel_port->cache.imr);
+		atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->cache.brgr);
+		atmel_uart_writel(port, atmel_port->rtor,
+				  atmel_port->cache.rtor);
+		atmel_uart_writel(port, ATMEL_US_TTGR, atmel_port->cache.ttgr);
+
+		if (atmel_port->fifo_size) {
+			atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_FIFOEN |
+					  ATMEL_US_RXFCLR | ATMEL_US_TXFLCLR);
+			atmel_uart_writel(port, ATMEL_US_FMR,
+					  atmel_port->cache.fmr);
+			atmel_uart_writel(port, ATMEL_US_FIER,
+					  atmel_port->cache.fimr);
+		}
+		atmel_start_rx(port);
+	}
+
 	spin_lock_irqsave(&atmel_port->lock_suspended, flags);
 	if (atmel_port->pending) {
 		atmel_handle_receive(port, atmel_port->pending);
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] tty/serial: atmel: ensure state is restored after suspending
  2017-02-03 22:53 [PATCH] tty/serial: atmel: ensure state is restored after suspending Alexandre Belloni
@ 2017-02-06  9:31 ` Nicolas Ferre
  2017-02-06 11:10 ` Richard Genoud
  1 sibling, 0 replies; 3+ messages in thread
From: Nicolas Ferre @ 2017-02-06  9:31 UTC (permalink / raw)
  To: Alexandre Belloni, Richard Genoud
  Cc: Greg Kroah-Hartman, linux-arm-kernel, linux-serial, linux-kernel

Le 03/02/2017 à 23:53, Alexandre Belloni a écrit :
> When going to suspend, the UART registers may be lost because the power to
> VDDcore is cut. This is not an issue in the normal case but when
> no_console_suspend is used, we need to restore the registers in order to
> get a functional console.
> 
> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>

Reviewed-by: Nicolas Ferre <nicolas.ferre@microchip.com>

Thanks,

> ---
>  drivers/tty/serial/atmel_serial.c | 44 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 44 insertions(+)
> 
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index 168b10cad47b..22e0a73c0cb7 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -175,6 +175,17 @@ struct atmel_uart_port {
>  	unsigned int		pending_status;
>  	spinlock_t		lock_suspended;
>  
> +	struct {
> +		u32		cr;
> +		u32		mr;
> +		u32		imr;
> +		u32		brgr;
> +		u32		rtor;
> +		u32		ttgr;
> +		u32		fmr;
> +		u32		fimr;
> +	} cache;
> +
>  	int (*prepare_rx)(struct uart_port *port);
>  	int (*prepare_tx)(struct uart_port *port);
>  	void (*schedule_rx)(struct uart_port *port);
> @@ -2649,6 +2660,20 @@ static int atmel_serial_suspend(struct platform_device *pdev,
>  			cpu_relax();
>  	}
>  
> +	if (atmel_is_console_port(port) && !console_suspend_enabled) {
> +		/* Cache register values as we won't get a full shutdown/startup
> +		 * cycle
> +		 */
> +		atmel_port->cache.mr = atmel_uart_readl(port, ATMEL_US_MR);
> +		atmel_port->cache.imr = atmel_uart_readl(port, ATMEL_US_IMR);
> +		atmel_port->cache.brgr = atmel_uart_readl(port, ATMEL_US_BRGR);
> +		atmel_port->cache.rtor = atmel_uart_readl(port,
> +							  atmel_port->rtor);
> +		atmel_port->cache.ttgr = atmel_uart_readl(port, ATMEL_US_TTGR);
> +		atmel_port->cache.fmr = atmel_uart_readl(port, ATMEL_US_FMR);
> +		atmel_port->cache.fimr = atmel_uart_readl(port, ATMEL_US_FIMR);
> +	}
> +
>  	/* we can not wake up if we're running on slow clock */
>  	atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
>  	if (atmel_serial_clk_will_stop()) {
> @@ -2671,6 +2696,25 @@ static int atmel_serial_resume(struct platform_device *pdev)
>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  	unsigned long flags;
>  
> +	if (atmel_is_console_port(port) && !console_suspend_enabled) {
> +		atmel_uart_writel(port, ATMEL_US_MR, atmel_port->cache.mr);
> +		atmel_uart_writel(port, ATMEL_US_IER, atmel_port->cache.imr);
> +		atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->cache.brgr);
> +		atmel_uart_writel(port, atmel_port->rtor,
> +				  atmel_port->cache.rtor);
> +		atmel_uart_writel(port, ATMEL_US_TTGR, atmel_port->cache.ttgr);
> +
> +		if (atmel_port->fifo_size) {
> +			atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_FIFOEN |
> +					  ATMEL_US_RXFCLR | ATMEL_US_TXFLCLR);
> +			atmel_uart_writel(port, ATMEL_US_FMR,
> +					  atmel_port->cache.fmr);
> +			atmel_uart_writel(port, ATMEL_US_FIER,
> +					  atmel_port->cache.fimr);
> +		}
> +		atmel_start_rx(port);
> +	}
> +
>  	spin_lock_irqsave(&atmel_port->lock_suspended, flags);
>  	if (atmel_port->pending) {
>  		atmel_handle_receive(port, atmel_port->pending);
> 


-- 
Nicolas Ferre

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] tty/serial: atmel: ensure state is restored after suspending
  2017-02-03 22:53 [PATCH] tty/serial: atmel: ensure state is restored after suspending Alexandre Belloni
  2017-02-06  9:31 ` Nicolas Ferre
@ 2017-02-06 11:10 ` Richard Genoud
  1 sibling, 0 replies; 3+ messages in thread
From: Richard Genoud @ 2017-02-06 11:10 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: Greg Kroah-Hartman, Nicolas Ferre, linux-arm-kernel, linux-serial,
	linux-kernel

Hi Alexandre,

On 03/02/2017 23:53, Alexandre Belloni wrote:
> When going to suspend, the UART registers may be lost because the power to
> VDDcore is cut. This is not an issue in the normal case but when
> no_console_suspend is used, we need to restore the registers in order to
> get a functional console.
> 
> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> ---
>  drivers/tty/serial/atmel_serial.c | 44 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 44 insertions(+)
> 
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index 168b10cad47b..22e0a73c0cb7 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -175,6 +175,17 @@ struct atmel_uart_port {
>  	unsigned int		pending_status;
>  	spinlock_t		lock_suspended;
>  
> +	struct {
> +		u32		cr;
> +		u32		mr;
> +		u32		imr;
> +		u32		brgr;
> +		u32		rtor;
> +		u32		ttgr;
> +		u32		fmr;
> +		u32		fimr;
> +	} cache;
> +
As struct cache is only used in suspend()/resume() we could add:
#ifdef CONFIG_PM / #endif
to remove it from atmel_uart_port when PM is not selected.
Even if I'm not a big fan of ifdefs, the suspend code is already
compiled out with #ifdef CONFIG_PM, so, at least, it would be consistent.

>  	int (*prepare_rx)(struct uart_port *port);
>  	int (*prepare_tx)(struct uart_port *port);
>  	void (*schedule_rx)(struct uart_port *port);
> @@ -2649,6 +2660,20 @@ static int atmel_serial_suspend(struct platform_device *pdev,
>  			cpu_relax();
>  	}
>  
> +	if (atmel_is_console_port(port) && !console_suspend_enabled) {
> +		/* Cache register values as we won't get a full shutdown/startup
> +		 * cycle
> +		 */
> +		atmel_port->cache.mr = atmel_uart_readl(port, ATMEL_US_MR);
> +		atmel_port->cache.imr = atmel_uart_readl(port, ATMEL_US_IMR);
> +		atmel_port->cache.brgr = atmel_uart_readl(port, ATMEL_US_BRGR);
> +		atmel_port->cache.rtor = atmel_uart_readl(port,
> +							  atmel_port->rtor);
> +		atmel_port->cache.ttgr = atmel_uart_readl(port, ATMEL_US_TTGR);
> +		atmel_port->cache.fmr = atmel_uart_readl(port, ATMEL_US_FMR);
> +		atmel_port->cache.fimr = atmel_uart_readl(port, ATMEL_US_FIMR);
> +	}
> +
>  	/* we can not wake up if we're running on slow clock */
>  	atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
>  	if (atmel_serial_clk_will_stop()) {
> @@ -2671,6 +2696,25 @@ static int atmel_serial_resume(struct platform_device *pdev)
>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  	unsigned long flags;
>  
> +	if (atmel_is_console_port(port) && !console_suspend_enabled) {
> +		atmel_uart_writel(port, ATMEL_US_MR, atmel_port->cache.mr);
> +		atmel_uart_writel(port, ATMEL_US_IER, atmel_port->cache.imr);
> +		atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->cache.brgr);
> +		atmel_uart_writel(port, atmel_port->rtor,
> +				  atmel_port->cache.rtor);
> +		atmel_uart_writel(port, ATMEL_US_TTGR, atmel_port->cache.ttgr);
> +
> +		if (atmel_port->fifo_size) {
> +			atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_FIFOEN |
> +					  ATMEL_US_RXFCLR | ATMEL_US_TXFLCLR);
> +			atmel_uart_writel(port, ATMEL_US_FMR,
> +					  atmel_port->cache.fmr);
> +			atmel_uart_writel(port, ATMEL_US_FIER,
> +					  atmel_port->cache.fimr);
> +		}
> +		atmel_start_rx(port);
> +	}
> +
>  	spin_lock_irqsave(&atmel_port->lock_suspended, flags);
>  	if (atmel_port->pending) {
>  		atmel_handle_receive(port, atmel_port->pending);
> 

Thanks !

Richard.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-02-06 11:10 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-02-03 22:53 [PATCH] tty/serial: atmel: ensure state is restored after suspending Alexandre Belloni
2017-02-06  9:31 ` Nicolas Ferre
2017-02-06 11:10 ` Richard Genoud

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).