diff mbox series

[PATCH/RFC,1/3] earlycon: Export clock and PM Domain info from FDT

Message ID efd9397662ff743f95298ca6aad4efdfa0ba1962.1716811405.git.geert+renesas@glider.be
State New
Headers show
Series pmdomain: renesas: rmobile-sysc: Remove serial console handling | expand

Commit Message

Geert Uytterhoeven May 27, 2024, 12:41 p.m. UTC
Earlycon relies on the serial port to be initialized by the firmware
and/or bootloader.  Linux is not aware of any hardware dependencies that
must be met to keep the port working, and thus cannot guarantee they
stay met, until the full serial driver takes over.

E.g. all unused clocks and unused PM Domains are disabled in a late
initcall.  As this happens after the full serial driver has taken over,
the serial port's clock and/or PM Domain are no longer deemed unused,
and this is typically not a problem.

However, if the serial port's clock or PM Domain is shared with another
device, and that other device is runtime-suspended before the full
serial driver has probed, the serial port's clock and/or PM Domain will
be disabled inadvertently.  Any subsequent serial console output will
cause a crash or system lock-up.

Provide a mechanism to let the clock and/or PM Domain subsystem or
drivers handle this, by exporting the clock and PM Domain dependencies
for the serial port, as available in the system's device tree.
Note that as this is done during early boot-up, the device_node
structure pointing to the earlycon console is not yet created, so this
has to resort to raw property data.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/tty/serial/earlycon.c | 14 +++++++++++++-
 include/linux/serial_core.h   | 10 ++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

Comments

Geert Uytterhoeven May 29, 2024, 9:01 a.m. UTC | #1
On Mon, May 27, 2024 at 2:41 PM Geert Uytterhoeven
<geert+renesas@glider.be> wrote:
> Earlycon relies on the serial port to be initialized by the firmware
> and/or bootloader.  Linux is not aware of any hardware dependencies that
> must be met to keep the port working, and thus cannot guarantee they
> stay met, until the full serial driver takes over.
>
> E.g. all unused clocks and unused PM Domains are disabled in a late
> initcall.  As this happens after the full serial driver has taken over,
> the serial port's clock and/or PM Domain are no longer deemed unused,
> and this is typically not a problem.
>
> However, if the serial port's clock or PM Domain is shared with another
> device, and that other device is runtime-suspended before the full
> serial driver has probed, the serial port's clock and/or PM Domain will
> be disabled inadvertently.  Any subsequent serial console output will
> cause a crash or system lock-up.
>
> Provide a mechanism to let the clock and/or PM Domain subsystem or
> drivers handle this, by exporting the clock and PM Domain dependencies
> for the serial port, as available in the system's device tree.
> Note that as this is done during early boot-up, the device_node
> structure pointing to the earlycon console is not yet created, so this
> has to resort to raw property data.
>
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>

> --- a/include/linux/serial_core.h
> +++ b/include/linux/serial_core.h
> @@ -954,6 +954,16 @@ static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED;
>  static inline int setup_earlycon(char *buf) { return 0; }
>  #endif
>
> +#ifdef CONFIG_OF_EARLY_FLATTREE

This should include a check  for CONFIG_SERIAL_EARLYCON.

> +extern const __be32 *earlycon_clocks, *earlycon_power_domains;
> +extern int earlycon_clocks_ncells, earlycon_power_domains_ncells;
> +#else
> +#define earlycon_clocks                        NULL
> +#define earlycon_clocks_ncells         0
> +#define earlycon_power_domains         NULL
> +#define earlycon_power_domains_ncells  0
> +#endif
> +
>  /* Variant of uart_console_registered() when the console_list_lock is held. */
>  static inline bool uart_console_registered_locked(struct uart_port *port)
>  {

Gr{oetje,eeting}s,

                        Geert
diff mbox series

Patch

diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index a5fbb6ed38aed681..abe4831d9685e2b8 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -250,11 +250,14 @@  early_param("earlycon", param_setup_earlycon);
 
 #ifdef CONFIG_OF_EARLY_FLATTREE
 
+const __be32 *earlycon_clocks, *earlycon_power_domains;
+int earlycon_clocks_ncells, earlycon_power_domains_ncells;
+
 int __init of_setup_earlycon(const struct earlycon_id *match,
 			     unsigned long node,
 			     const char *options)
 {
-	int err;
+	int err, size;
 	struct uart_port *port = &early_console_dev.port;
 	const __be32 *val;
 	bool big_endian;
@@ -309,6 +312,15 @@  int __init of_setup_earlycon(const struct earlycon_id *match,
 	if (val)
 		port->uartclk = be32_to_cpu(*val);
 
+	earlycon_clocks = of_get_flat_dt_prop(node, "clocks", &size);
+	if (earlycon_clocks)
+		earlycon_clocks_ncells = size / sizeof(u32);
+
+	earlycon_power_domains = of_get_flat_dt_prop(node, "power-domains",
+						     &size);
+	if (earlycon_power_domains)
+		earlycon_power_domains_ncells = size / sizeof(u32);
+
 	if (options) {
 		early_console_dev.baud = simple_strtoul(options, NULL, 0);
 		strscpy(early_console_dev.options, options,
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 8cb65f50e830c8d4..70689a3363951dac 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -954,6 +954,16 @@  static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED;
 static inline int setup_earlycon(char *buf) { return 0; }
 #endif
 
+#ifdef CONFIG_OF_EARLY_FLATTREE
+extern const __be32 *earlycon_clocks, *earlycon_power_domains;
+extern int earlycon_clocks_ncells, earlycon_power_domains_ncells;
+#else
+#define earlycon_clocks			NULL
+#define earlycon_clocks_ncells		0
+#define earlycon_power_domains		NULL
+#define earlycon_power_domains_ncells	0
+#endif
+
 /* Variant of uart_console_registered() when the console_list_lock is held. */
 static inline bool uart_console_registered_locked(struct uart_port *port)
 {