Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://lore.kernel.org/r/20250207113313.545432-1-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Claudiu Beznea and committed by
Greg Kroah-Hartman
22a6984c 1f0cfc68

+69 -2
+69 -2
drivers/tty/serial/sh-sci.c
··· 104 104 u8 offset, size; 105 105 }; 106 106 107 + struct sci_suspend_regs { 108 + u16 scsmr; 109 + u16 scscr; 110 + u16 scfcr; 111 + u16 scsptr; 112 + u8 scbrr; 113 + u8 semr; 114 + }; 115 + 107 116 struct sci_port_params { 108 117 const struct plat_sci_reg regs[SCIx_NR_REGS]; 109 118 unsigned int fifosize; ··· 143 134 struct dma_chan *chan_tx; 144 135 struct dma_chan *chan_rx; 145 136 137 + struct reset_control *rstc; 138 + 146 139 #ifdef CONFIG_SERIAL_SH_SCI_DMA 147 140 struct dma_chan *chan_tx_saved; 148 141 struct dma_chan *chan_rx_saved; ··· 164 153 int rx_trigger; 165 154 struct timer_list rx_fifo_timer; 166 155 int rx_fifo_timeout; 156 + struct sci_suspend_regs suspend_regs; 167 157 u16 hscif_tot; 168 158 169 159 bool has_rtscts; ··· 3386 3374 } 3387 3375 3388 3376 sp = &sci_ports[id]; 3377 + sp->rstc = rstc; 3389 3378 *dev_id = id; 3390 3379 3391 3380 p->type = SCI_OF_TYPE(data); ··· 3559 3546 return 0; 3560 3547 } 3561 3548 3549 + static void sci_console_save(struct sci_port *s) 3550 + { 3551 + struct sci_suspend_regs *regs = &s->suspend_regs; 3552 + struct uart_port *port = &s->port; 3553 + 3554 + if (sci_getreg(port, SCSMR)->size) 3555 + regs->scsmr = sci_serial_in(port, SCSMR); 3556 + if (sci_getreg(port, SCSCR)->size) 3557 + regs->scscr = sci_serial_in(port, SCSCR); 3558 + if (sci_getreg(port, SCFCR)->size) 3559 + regs->scfcr = sci_serial_in(port, SCFCR); 3560 + if (sci_getreg(port, SCSPTR)->size) 3561 + regs->scsptr = sci_serial_in(port, SCSPTR); 3562 + if (sci_getreg(port, SCBRR)->size) 3563 + regs->scbrr = sci_serial_in(port, SCBRR); 3564 + if (sci_getreg(port, SEMR)->size) 3565 + regs->semr = sci_serial_in(port, SEMR); 3566 + } 3567 + 3568 + static void sci_console_restore(struct sci_port *s) 3569 + { 3570 + struct sci_suspend_regs *regs = &s->suspend_regs; 3571 + struct uart_port *port = &s->port; 3572 + 3573 + if (sci_getreg(port, SCSMR)->size) 3574 + sci_serial_out(port, SCSMR, regs->scsmr); 3575 + if (sci_getreg(port, SCSCR)->size) 3576 + sci_serial_out(port, SCSCR, regs->scscr); 3577 + if (sci_getreg(port, SCFCR)->size) 3578 + sci_serial_out(port, SCFCR, regs->scfcr); 3579 + if (sci_getreg(port, SCSPTR)->size) 3580 + sci_serial_out(port, SCSPTR, regs->scsptr); 3581 + if (sci_getreg(port, SCBRR)->size) 3582 + sci_serial_out(port, SCBRR, regs->scbrr); 3583 + if (sci_getreg(port, SEMR)->size) 3584 + sci_serial_out(port, SEMR, regs->semr); 3585 + } 3586 + 3562 3587 static __maybe_unused int sci_suspend(struct device *dev) 3563 3588 { 3564 3589 struct sci_port *sport = dev_get_drvdata(dev); 3565 3590 3566 - if (sport) 3591 + if (sport) { 3567 3592 uart_suspend_port(&sci_uart_driver, &sport->port); 3593 + 3594 + if (!console_suspend_enabled && uart_console(&sport->port)) 3595 + sci_console_save(sport); 3596 + else 3597 + return reset_control_assert(sport->rstc); 3598 + } 3568 3599 3569 3600 return 0; 3570 3601 } ··· 3617 3560 { 3618 3561 struct sci_port *sport = dev_get_drvdata(dev); 3619 3562 3620 - if (sport) 3563 + if (sport) { 3564 + if (!console_suspend_enabled && uart_console(&sport->port)) { 3565 + sci_console_restore(sport); 3566 + } else { 3567 + int ret = reset_control_deassert(sport->rstc); 3568 + 3569 + if (ret) 3570 + return ret; 3571 + } 3572 + 3621 3573 uart_resume_port(&sci_uart_driver, &sport->port); 3574 + } 3622 3575 3623 3576 return 0; 3624 3577 }