[PATCH 1/2] console: provide best-effort clk_get_for_console helper
Ahmad Fatoum
a.fatoum at pengutronix.de
Tue Nov 14 00:33:47 PST 2023
On 14.11.23 09:23, Sascha Hauer wrote:
> On Mon, Nov 13, 2023 at 04:02:56PM +0100, Ahmad Fatoum wrote:
>> On 13.11.23 14:03, Sascha Hauer wrote:
>>> On Thu, Nov 09, 2023 at 12:47:06PM +0100, Ahmad Fatoum wrote:
>>>> From: Ahmad Fatoum <ahmad at a3f.at>
>>>>
>>>> clk_get will return -EPROBE_DEFER if clock provider hasn't yet been
>>>> probed. In a system with deep probe enabled, dependencies are probed
>>>> on demand, so a -EPROBE_DEFER return is final and the console probe
>>>> will never succeed.
>>>>
>>>> CONFIG_DEBUG_LL is often used to debug this, but because the low-level
>>>> console is not interactive, it's a bit cumbersome. Improve upon this a
>>>> bit, by providing a clk_get_for_console helper that returns NULL if and
>>>> only if we are sure that a clock provider will not be probed.
>>>>
>>>> In that case, the driver can skip code paths initialization code and
>>>> baud rate setting dependent on having access to the clock and still
>>>> register a console that reuses what was set up by CONFIG_DEBUG_LL.
>>>>
>>>> Signed-off-by: Ahmad Fatoum <ahmad at a3f.at>
>>>> ---
>>>> include/console.h | 26 ++++++++++++++++++++++++++
>>>> include/linux/clk.h | 21 +++++++++++++++++++++
>>>> 2 files changed, 47 insertions(+)
>>>>
>>>> diff --git a/include/console.h b/include/console.h
>>>> index 586b68f73301..b8c901801e9f 100644
>>>> --- a/include/console.h
>>>> +++ b/include/console.h
>>>> @@ -8,6 +8,7 @@
>>>> #define _CONSOLE_H_
>>>>
>>>> #include <param.h>
>>>> +#include <linux/clk.h>
>>>> #include <linux/list.h>
>>>> #include <driver.h>
>>>> #include <serdev.h>
>>>> @@ -208,4 +209,29 @@ static inline void console_ctrlc_allow(void) { }
>>>> static inline void console_ctrlc_forbid(void) { }
>>>> #endif
>>>>
>>>> +/**
>>>> + * clk_get_for_console - get clock, ignoring known unavailable clock controller
>>>> + * @dev: device for clock "consumer"
>>>> + * @id: clock consumer ID
>>>> + *
>>>> + * Return: a struct clk corresponding to the clock producer, a
>>>> + * valid IS_ERR() condition containing errno or NULL if it could
>>>> + * be determined that the clock producer will never be probed in
>>>> + * absence of modules. The NULL return allows serial drivers to
>>>> + * skip clock handling and rely on CONFIG_DEBUG_LL.
>>>> + */
>>>> +static inline struct clk *clk_get_for_console(struct device *dev, const char *id)
>>>> +{
>>>> + struct clk *clk;
>>>> +
>>>> + if (!IS_ENABLED(CONFIG_DEBUG_LL))
>>>> + return clk_get(dev, id);
>>>
>>> There are several SoCs out there where the UART is enabled by the ROM
>>> already, on these we don't need to have CONFIG_DEBUG_LL enabled for a
>>> working UART.
>>
>> Those SoCs can still implement CONFIG_DEBUG_LL and just skip the
>> initialization step.
>>
>>> Maybe testing for the UART enable bit in probe() would be a better
>>> indication that the UART is already in a working state?
>>
>> If clk turns out to be not enabled, system would hang on e.g. i.MX.
>
> That can happen with your patch as well as you don't limit the
> usage of clk_get_for_console() to the UART putc_ll is configured
> for. Initializing one of the other UARTs might hang your system
> once you access a register.
That's why it's a debugging measure behind DEBUG_LL, so you need to
opt-in into this.
>
>>
>> This is a mere debugging measure for SoCs with complex clock controllers
>> backed by firmware, so I think having to enable CONFIG_DEBUG_LL to use
>> is acceptable.
>
> Another option would be to implement and use a GETC_LL() macro. This
> requires some thinking how this can be integrated into the console
> code, but would in the end be more universally usable. With this we
> could make barebox interactive even when the real serial driver is
> not compiled in (or not even yet existing). See below for a prototype.
I don't think the DEBUG_LL API should be extended. Rather we should
look into how to inherit PBL console in barebox proper. But that's a
bigger change, thus the middle ground in my patch.
Cheers,
Ahmad
>
> Sascha
>
> ----------------------------8<-----------------------------
>
> From a737458a64718f96c8d5267551895b0fcea23089 Mon Sep 17 00:00:00 2001
> From: Sascha Hauer <s.hauer at pengutronix.de>
> Date: Tue, 14 Nov 2023 09:22:24 +0100
> Subject: [PATCH] debug_ll: implement lowlevel debug input functions
>
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> ---
> arch/arm/boards/tqmba9xxxca/lowlevel.c | 1 +
> common/console.c | 6 ++++++
> common/startup.c | 3 ++-
> include/debug_ll.h | 16 +++++++++++++++
> include/mach/imx/debug_ll.h | 28 ++++++++++++++++++++++++++
> include/serial/lpuart32.h | 12 +++++++++++
> 6 files changed, 65 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/boards/tqmba9xxxca/lowlevel.c b/arch/arm/boards/tqmba9xxxca/lowlevel.c
> index 8207cd9515..761ca38dc4 100644
> --- a/arch/arm/boards/tqmba9xxxca/lowlevel.c
> +++ b/arch/arm/boards/tqmba9xxxca/lowlevel.c
> @@ -17,6 +17,7 @@ static noinline void tqma9352_mba93xxca_continue(void)
> void *base = IOMEM(MX9_UART1_BASE_ADDR);
> void *muxbase = IOMEM(MX9_IOMUXC_BASE_ADDR);
>
> + writel(0x0, muxbase + 0x180);
> writel(0x0, muxbase + 0x184);
> imx9_uart_setup(IOMEM(base));
> pbl_set_putc(lpuart32_putc, base + 0x10);
> diff --git a/common/console.c b/common/console.c
> index 7e43a9b5fc..4209561db9 100644
> --- a/common/console.c
> +++ b/common/console.c
> @@ -452,6 +452,9 @@ static int getc_raw(void)
> struct console_device *cdev;
> int active = 0;
>
> + if (initialized < CONSOLE_INIT_FULL)
> + return getc_ll();
> +
> while (1) {
> for_each_console(cdev) {
> if (!(cdev->f_active & CONSOLE_STDIN))
> @@ -478,6 +481,9 @@ static int tstc_raw(void)
> {
> struct console_device *cdev;
>
> + if (initialized < CONSOLE_INIT_FULL)
> + return tstc_ll();
> +
> for_each_console(cdev) {
> if (!(cdev->f_active & CONSOLE_STDIN))
> continue;
> diff --git a/common/startup.c b/common/startup.c
> index bbba72f892..1f15dc5b91 100644
> --- a/common/startup.c
> +++ b/common/startup.c
> @@ -174,11 +174,12 @@ enum autoboot_state do_autoboot_countdown(void)
> if (autoboot_state != AUTOBOOT_UNKNOWN)
> return autoboot_state;
>
> +#ifndef GETC_LL
> if (!console_get_first_active()) {
> printf("\nNon-interactive console, booting system\n");
> return autoboot_state = AUTOBOOT_BOOT;
> }
> -
> +#endif
> if (global_autoboot_state != AUTOBOOT_COUNTDOWN)
> return global_autoboot_state;
>
> diff --git a/include/debug_ll.h b/include/debug_ll.h
> index 0128ab524a..84933657e6 100644
> --- a/include/debug_ll.h
> +++ b/include/debug_ll.h
> @@ -29,6 +29,22 @@ static inline void putc_ll(char value)
> PUTC_LL(value);
> }
>
> +static inline int getc_ll(void)
> +{
> +#ifdef GETC_LL
> + return GETC_LL();
> +#endif
> + return -EAGAIN;
> +}
> +
> +static inline int tstc_ll(void)
> +{
> +#ifdef TSTC_LL
> + return TSTC_LL();
> +#endif
> + return 0;
> +}
> +
> static inline void puthexc_ll(unsigned char value)
> {
> int i; unsigned char ch;
> diff --git a/include/mach/imx/debug_ll.h b/include/mach/imx/debug_ll.h
> index 618cbc784e..e5abf1a216 100644
> --- a/include/mach/imx/debug_ll.h
> +++ b/include/mach/imx/debug_ll.h
> @@ -134,6 +134,34 @@ static inline void PUTC_LL(int c)
> imx_uart_putc(base, c);
> }
>
> +#define GETC_LL GETC_LL
> +static inline int GETC_LL(void)
> +{
> + void __iomem *base = IOMEM(IMX_UART_BASE(IMX_DEBUG_SOC,
> + CONFIG_DEBUG_IMX_UART_PORT));
> +
> + if (!base)
> + return -EINVAL;
> +
> + if (IS_ENABLED(CONFIG_DEBUG_IMX9_UART))
> + return lpuart32_getc(base + 0x10);
> + return -ENOTSUPP;
> +}
> +
> +#define TSTC_LL TSTC_LL
> +static inline int TSTC_LL(void)
> +{
> + void __iomem *base = IOMEM(IMX_UART_BASE(IMX_DEBUG_SOC,
> + CONFIG_DEBUG_IMX_UART_PORT));
> +
> + if (!base)
> + return -EINVAL;
> +
> + if (IS_ENABLED(CONFIG_DEBUG_IMX9_UART))
> + return lpuart32_tstc(base + 0x10);
> + return -ENOTSUPP;
> +}
> +
> #else
>
> static inline void imx50_uart_setup_ll(void) {}
> diff --git a/include/serial/lpuart32.h b/include/serial/lpuart32.h
> index 12526ee0ae..9df5e0937f 100644
> --- a/include/serial/lpuart32.h
> +++ b/include/serial/lpuart32.h
> @@ -155,6 +155,18 @@ static inline void lpuart32_putc(void __iomem *base, int c)
> writel(c, base + LPUART32_UARTDATA);
> }
>
> +static inline int lpuart32_tstc(void __iomem *base)
> +{
> + return readl(base + LPUART32_UARTSTAT) & LPUART32_UARTSTAT_RDRF;
> +}
> +
> +static inline int lpuart32_getc(void __iomem *base)
> +{
> + while (!lpuart32_tstc(base));
> +
> + return readl(base + LPUART32_UARTDATA) & 0xff;
> +}
> +
> static inline void imx9_uart_setup(void __iomem *uartbase)
> {
> /*
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
More information about the barebox
mailing list