Commit 22a6984c authored by Claudiu Beznea's avatar Claudiu Beznea Committed by Greg Kroah-Hartman
Browse files

serial: sh-sci: Update the suspend/resume support



The Renesas RZ/G3S supports a power saving mode where power to most of the
SoC components is turned off. When returning from this power saving mode,
SoC components need to be re-configured.

The SCIFs on the Renesas RZ/G3S need to be re-configured as well when
returning from this power saving mode. The sh-sci code already configures
the SCIF clocks, power domain and registers by calling uart_resume_port()
in sci_resume(). On suspend path the SCIF UART ports are suspended
accordingly (by calling uart_suspend_port() in sci_suspend()). The only
missing setting is the reset signal. For this assert/de-assert the reset
signal on driver suspend/resume.

In case the no_console_suspend is specified by the user, the registers need
to be saved on suspend path and restore on resume path. To do this the
sci_console_save()/sci_console_restore() functions were added. There is no
need to cache/restore the status or FIFO registers. Only the control
registers. The registers that will be saved/restored on suspend/resume are
specified by the struct sci_suspend_regs data structure.

Signed-off-by: default avatarClaudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Reviewed-by: default avatarGeert Uytterhoeven <geert+renesas@glider.be>
Link: https://lore.kernel.org/r/20250207113313.545432-1-claudiu.beznea.uj@bp.renesas.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1f0cfc68
Loading
Loading
Loading
Loading
+69 −2
Original line number Diff line number Diff line
@@ -104,6 +104,15 @@ struct plat_sci_reg {
	u8 offset, size;
};

struct sci_suspend_regs {
	u16 scsmr;
	u16 scscr;
	u16 scfcr;
	u16 scsptr;
	u8 scbrr;
	u8 semr;
};

struct sci_port_params {
	const struct plat_sci_reg regs[SCIx_NR_REGS];
	unsigned int fifosize;
@@ -134,6 +143,8 @@ struct sci_port {
	struct dma_chan			*chan_tx;
	struct dma_chan			*chan_rx;

	struct reset_control		*rstc;

#ifdef CONFIG_SERIAL_SH_SCI_DMA
	struct dma_chan			*chan_tx_saved;
	struct dma_chan			*chan_rx_saved;
@@ -153,6 +164,7 @@ struct sci_port {
	int				rx_trigger;
	struct timer_list		rx_fifo_timer;
	int				rx_fifo_timeout;
	struct sci_suspend_regs		suspend_regs;
	u16				hscif_tot;

	bool has_rtscts;
@@ -3374,6 +3386,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
	}

	sp = &sci_ports[id];
	sp->rstc = rstc;
	*dev_id = id;

	p->type = SCI_OF_TYPE(data);
@@ -3546,13 +3559,57 @@ static int sci_probe(struct platform_device *dev)
	return 0;
}

static void sci_console_save(struct sci_port *s)
{
	struct sci_suspend_regs *regs = &s->suspend_regs;
	struct uart_port *port = &s->port;

	if (sci_getreg(port, SCSMR)->size)
		regs->scsmr = sci_serial_in(port, SCSMR);
	if (sci_getreg(port, SCSCR)->size)
		regs->scscr = sci_serial_in(port, SCSCR);
	if (sci_getreg(port, SCFCR)->size)
		regs->scfcr = sci_serial_in(port, SCFCR);
	if (sci_getreg(port, SCSPTR)->size)
		regs->scsptr = sci_serial_in(port, SCSPTR);
	if (sci_getreg(port, SCBRR)->size)
		regs->scbrr = sci_serial_in(port, SCBRR);
	if (sci_getreg(port, SEMR)->size)
		regs->semr = sci_serial_in(port, SEMR);
}

static void sci_console_restore(struct sci_port *s)
{
	struct sci_suspend_regs *regs = &s->suspend_regs;
	struct uart_port *port = &s->port;

	if (sci_getreg(port, SCSMR)->size)
		sci_serial_out(port, SCSMR, regs->scsmr);
	if (sci_getreg(port, SCSCR)->size)
		sci_serial_out(port, SCSCR, regs->scscr);
	if (sci_getreg(port, SCFCR)->size)
		sci_serial_out(port, SCFCR, regs->scfcr);
	if (sci_getreg(port, SCSPTR)->size)
		sci_serial_out(port, SCSPTR, regs->scsptr);
	if (sci_getreg(port, SCBRR)->size)
		sci_serial_out(port, SCBRR, regs->scbrr);
	if (sci_getreg(port, SEMR)->size)
		sci_serial_out(port, SEMR, regs->semr);
}

static __maybe_unused int sci_suspend(struct device *dev)
{
	struct sci_port *sport = dev_get_drvdata(dev);

	if (sport)
	if (sport) {
		uart_suspend_port(&sci_uart_driver, &sport->port);

		if (!console_suspend_enabled && uart_console(&sport->port))
			sci_console_save(sport);
		else
			return reset_control_assert(sport->rstc);
	}

	return 0;
}

@@ -3560,8 +3617,18 @@ static __maybe_unused int sci_resume(struct device *dev)
{
	struct sci_port *sport = dev_get_drvdata(dev);

	if (sport)
	if (sport) {
		if (!console_suspend_enabled && uart_console(&sport->port)) {
			sci_console_restore(sport);
		} else {
			int ret = reset_control_deassert(sport->rstc);

			if (ret)
				return ret;
		}

		uart_resume_port(&sci_uart_driver, &sport->port);
	}

	return 0;
}