All of lore.kernel.org
 help / color / mirror / Atom feed
From: Grygorii Strashko <grygorii.strashko@ti.com>
To: Tony Lindgren <tony@atomide.com>,
	Daniel Lezcano <daniel.lezcano@linaro.org>,
	Thomas Gleixner <tglx@linutronix.de>
Cc: <linux-kernel@vger.kernel.org>, <linux-omap@vger.kernel.org>,
	<linux-arm-kernel@lists.infradead.org>,
	Carlos Hernandez <ceh@ti.com>
Subject: Re: [PATCH] clocksource/drivers/timer-ti-dm: Fix suspend and resume for am3 and am4
Date: Wed, 15 Jul 2020 13:17:33 +0300	[thread overview]
Message-ID: <1972bace-e9d1-b901-eb33-b4081a4b175d@ti.com> (raw)
In-Reply-To: <20200713162601.6829-1-tony@atomide.com>



On 13/07/2020 19:26, Tony Lindgren wrote:
> Carlos Hernandez <ceh@ti.com> reported that we now have a suspend and
> resume regresssion on am3 and am4 compared to the earlier kernels. While
> suspend and resume works with v5.8-rc3, we now get errors with rtcwake:
> 
> pm33xx pm33xx: PM: Could not transition all powerdomains to target state
> ...
> rtcwake: write error
> 
> This is because we now fail to idle the system timer clocks that the
> idle code checks and the error gets propagated to the rtcwake.
> 
> Turns out there are several issues that need to be fixed:
> 
> 1. Ignore no-idle and no-reset configured timers for the ti-sysc
>     interconnect target driver as otherwise it will keep the system timer
>     clocks enabled
> 
> 2. Toggle the system timer functional clock for suspend for am3 and am4
>     (but not for clocksource on am3)
> 
> 3. Only reconfigure type1 timers in dmtimer_systimer_disable()
> 
> 4. Use of_machine_is_compatible() instead of of_device_is_compatible()
>     for checking the SoC type
> 
> Fixes: 52762fbd1c47 ("clocksource/drivers/timer-ti-dm: Add clockevent and clocksource support")
> Reported-by: Carlos Hernandez <ceh@ti.com>
> Signed-off-by: Tony Lindgren <tony@atomide.com>
> ---
>   drivers/bus/ti-sysc.c                      | 22 +++++++++++
>   drivers/clocksource/timer-ti-dm-systimer.c | 46 +++++++++++++++++-----
>   2 files changed, 58 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
> --- a/drivers/bus/ti-sysc.c
> +++ b/drivers/bus/ti-sysc.c
> @@ -2877,6 +2877,24 @@ static int sysc_check_disabled_devices(struct sysc *ddata)
>   	return error;
>   }
>   
> +/*
> + * Ignore timers tagged with no-reset and no-idle. These are likely in use,
> + * for example by drivers/clocksource/timer-ti-dm-systimer.c. If more checks
> + * are needed, we could also look at the timer register configuration.
> + */
> +static int sysc_check_active_timer(struct sysc *ddata)
> +{
> +	if (ddata->cap->type != TI_SYSC_OMAP2_TIMER &&
> +	    ddata->cap->type != TI_SYSC_OMAP4_TIMER)
> +		return 0;
> +
> +	if ((ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) &&
> +	    (ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE))
> +		return -EBUSY;
> +
> +	return 0;
> +}
> +
>   static const struct of_device_id sysc_match_table[] = {
>   	{ .compatible = "simple-bus", },
>   	{ /* sentinel */ },
> @@ -2933,6 +2951,10 @@ static int sysc_probe(struct platform_device *pdev)
>   	if (error)
>   		return error;
>   
> +	error = sysc_check_active_timer(ddata);
> +	if (error)
> +		return error;
> +
>   	error = sysc_get_clocks(ddata);
>   	if (error)
>   		return error;
> diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c
> --- a/drivers/clocksource/timer-ti-dm-systimer.c
> +++ b/drivers/clocksource/timer-ti-dm-systimer.c
> @@ -19,7 +19,7 @@
>   /* For type1, set SYSC_OMAP2_CLOCKACTIVITY for fck off on idle, l4 clock on */
>   #define DMTIMER_TYPE1_ENABLE	((1 << 9) | (SYSC_IDLE_SMART << 3) | \
>   				 SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_AUTOIDLE)
> -
> +#define DMTIMER_TYPE1_DISABLE	(SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE)
>   #define DMTIMER_TYPE2_ENABLE	(SYSC_IDLE_SMART_WKUP << 2)
>   #define DMTIMER_RESET_WAIT	100000
>   
> @@ -44,6 +44,8 @@ struct dmtimer_systimer {
>   	u8 ctrl;
>   	u8 wakeup;
>   	u8 ifctrl;
> +	struct clk *fck;
> +	struct clk *ick;
>   	unsigned long rate;
>   };
>   
> @@ -298,16 +300,20 @@ static void __init dmtimer_systimer_select_best(void)
>   }
>   
>   /* Interface clocks are only available on some SoCs variants */
> -static int __init dmtimer_systimer_init_clock(struct device_node *np,
> +static int __init dmtimer_systimer_init_clock(struct dmtimer_systimer *t,
> +					      struct device_node *np,
>   					      const char *name,
>   					      unsigned long *rate)
>   {
>   	struct clk *clock;
>   	unsigned long r;
> +	bool is_ick = false;
>   	int error;
>   
> +	is_ick = !strncmp(name, "ick", 3);
> +
>   	clock = of_clk_get_by_name(np, name);
> -	if ((PTR_ERR(clock) == -EINVAL) && !strncmp(name, "ick", 3))
> +	if ((PTR_ERR(clock) == -EINVAL) && is_ick)
>   		return 0;
>   	else if (IS_ERR(clock))
>   		return PTR_ERR(clock);
> @@ -320,6 +326,11 @@ static int __init dmtimer_systimer_init_clock(struct device_node *np,
>   	if (!r)
>   		return -ENODEV;
>   
> +	if (is_ick)
> +		t->ick = clock;
> +	else
> +		t->fck = clock;
> +
>   	*rate = r;
>   
>   	return 0;
> @@ -339,7 +350,10 @@ static void dmtimer_systimer_enable(struct dmtimer_systimer *t)
>   
>   static void dmtimer_systimer_disable(struct dmtimer_systimer *t)
>   {
> -	writel_relaxed(0, t->base + t->sysc);
> +	if (!dmtimer_systimer_revision1(t))
> +		return;
> +
> +	writel_relaxed(DMTIMER_TYPE1_DISABLE, t->base + t->sysc);
>   }
>   
>   static int __init dmtimer_systimer_setup(struct device_node *np,
> @@ -366,13 +380,13 @@ static int __init dmtimer_systimer_setup(struct device_node *np,
>   		pr_err("%s: clock source init failed: %i\n", __func__, error);
>   
>   	/* For ti-sysc, we have timer clocks at the parent module level */
> -	error = dmtimer_systimer_init_clock(np->parent, "fck", &rate);
> +	error = dmtimer_systimer_init_clock(t, np->parent, "fck", &rate);
>   	if (error)
>   		goto err_unmap;
>   
>   	t->rate = rate;
>   
> -	error = dmtimer_systimer_init_clock(np->parent, "ick", &rate);
> +	error = dmtimer_systimer_init_clock(t, np->parent, "ick", &rate);
>   	if (error)
>   		goto err_unmap;
>   
> @@ -496,12 +510,18 @@ static void omap_clockevent_idle(struct clock_event_device *evt)
>   	struct dmtimer_systimer *t = &clkevt->t;
>   
>   	dmtimer_systimer_disable(t);
> +	clk_disable(t->fck);
>   }
>   
>   static void omap_clockevent_unidle(struct clock_event_device *evt)
>   {
>   	struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt);
>   	struct dmtimer_systimer *t = &clkevt->t;
> +	int error;
> +
> +	error = clk_enable(t->fck);
> +	if (error)
> +		pr_err("could not enable timer fck on resume: %i\n", error);
>   
>   	dmtimer_systimer_enable(t);
>   	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena);
> @@ -570,8 +590,8 @@ static int __init dmtimer_clockevent_init(struct device_node *np)
>   					3, /* Timer internal resynch latency */
>   					0xffffffff);
>   
> -	if (of_device_is_compatible(np, "ti,am33xx") ||
> -	    of_device_is_compatible(np, "ti,am43")) {
> +	if (of_machine_is_compatible("ti,am33xx") ||
> +	    of_machine_is_compatible("ti,am43")) {
>   		dev->suspend = omap_clockevent_idle;
>   		dev->resume = omap_clockevent_unidle;
>   	}
> @@ -616,12 +636,18 @@ static void dmtimer_clocksource_suspend(struct clocksource *cs)
>   
>   	clksrc->loadval = readl_relaxed(t->base + t->counter);
>   	dmtimer_systimer_disable(t);
> +	clk_disable(t->fck);
>   }
>   
>   static void dmtimer_clocksource_resume(struct clocksource *cs)
>   {
>   	struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs);
>   	struct dmtimer_systimer *t = &clksrc->t;
> +	int error;
> +
> +	error = clk_enable(t->fck);
> +	if (error)
> +		pr_err("could not enable timer fck on resume: %i\n", error);
>   
>   	dmtimer_systimer_enable(t);
>   	writel_relaxed(clksrc->loadval, t->base + t->counter);
> @@ -653,8 +679,8 @@ static int __init dmtimer_clocksource_init(struct device_node *np)
>   	dev->mask = CLOCKSOURCE_MASK(32);
>   	dev->flags = CLOCK_SOURCE_IS_CONTINUOUS;
>   
> -	if (of_device_is_compatible(np, "ti,am33xx") ||
> -	    of_device_is_compatible(np, "ti,am43")) {
> +	/* Unlike for clockevent, legacy code sets suspend only for am4 */
> +	if (of_machine_is_compatible("ti,am43")) {
>   		dev->suspend = dmtimer_clocksource_suspend;
>   		dev->resume = dmtimer_clocksource_resume;
>   	}
> 

It might be better to use SOC_BUS infra here, which is available on OMAP platforms by default,
instead if DT. What do you think?

-- 
Best regards,
grygorii

WARNING: multiple messages have this Message-ID (diff)
From: Grygorii Strashko <grygorii.strashko@ti.com>
To: Tony Lindgren <tony@atomide.com>,
	Daniel Lezcano <daniel.lezcano@linaro.org>,
	Thomas Gleixner <tglx@linutronix.de>
Cc: Carlos Hernandez <ceh@ti.com>,
	linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH] clocksource/drivers/timer-ti-dm: Fix suspend and resume for am3 and am4
Date: Wed, 15 Jul 2020 13:17:33 +0300	[thread overview]
Message-ID: <1972bace-e9d1-b901-eb33-b4081a4b175d@ti.com> (raw)
In-Reply-To: <20200713162601.6829-1-tony@atomide.com>



On 13/07/2020 19:26, Tony Lindgren wrote:
> Carlos Hernandez <ceh@ti.com> reported that we now have a suspend and
> resume regresssion on am3 and am4 compared to the earlier kernels. While
> suspend and resume works with v5.8-rc3, we now get errors with rtcwake:
> 
> pm33xx pm33xx: PM: Could not transition all powerdomains to target state
> ...
> rtcwake: write error
> 
> This is because we now fail to idle the system timer clocks that the
> idle code checks and the error gets propagated to the rtcwake.
> 
> Turns out there are several issues that need to be fixed:
> 
> 1. Ignore no-idle and no-reset configured timers for the ti-sysc
>     interconnect target driver as otherwise it will keep the system timer
>     clocks enabled
> 
> 2. Toggle the system timer functional clock for suspend for am3 and am4
>     (but not for clocksource on am3)
> 
> 3. Only reconfigure type1 timers in dmtimer_systimer_disable()
> 
> 4. Use of_machine_is_compatible() instead of of_device_is_compatible()
>     for checking the SoC type
> 
> Fixes: 52762fbd1c47 ("clocksource/drivers/timer-ti-dm: Add clockevent and clocksource support")
> Reported-by: Carlos Hernandez <ceh@ti.com>
> Signed-off-by: Tony Lindgren <tony@atomide.com>
> ---
>   drivers/bus/ti-sysc.c                      | 22 +++++++++++
>   drivers/clocksource/timer-ti-dm-systimer.c | 46 +++++++++++++++++-----
>   2 files changed, 58 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
> --- a/drivers/bus/ti-sysc.c
> +++ b/drivers/bus/ti-sysc.c
> @@ -2877,6 +2877,24 @@ static int sysc_check_disabled_devices(struct sysc *ddata)
>   	return error;
>   }
>   
> +/*
> + * Ignore timers tagged with no-reset and no-idle. These are likely in use,
> + * for example by drivers/clocksource/timer-ti-dm-systimer.c. If more checks
> + * are needed, we could also look at the timer register configuration.
> + */
> +static int sysc_check_active_timer(struct sysc *ddata)
> +{
> +	if (ddata->cap->type != TI_SYSC_OMAP2_TIMER &&
> +	    ddata->cap->type != TI_SYSC_OMAP4_TIMER)
> +		return 0;
> +
> +	if ((ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) &&
> +	    (ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE))
> +		return -EBUSY;
> +
> +	return 0;
> +}
> +
>   static const struct of_device_id sysc_match_table[] = {
>   	{ .compatible = "simple-bus", },
>   	{ /* sentinel */ },
> @@ -2933,6 +2951,10 @@ static int sysc_probe(struct platform_device *pdev)
>   	if (error)
>   		return error;
>   
> +	error = sysc_check_active_timer(ddata);
> +	if (error)
> +		return error;
> +
>   	error = sysc_get_clocks(ddata);
>   	if (error)
>   		return error;
> diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c
> --- a/drivers/clocksource/timer-ti-dm-systimer.c
> +++ b/drivers/clocksource/timer-ti-dm-systimer.c
> @@ -19,7 +19,7 @@
>   /* For type1, set SYSC_OMAP2_CLOCKACTIVITY for fck off on idle, l4 clock on */
>   #define DMTIMER_TYPE1_ENABLE	((1 << 9) | (SYSC_IDLE_SMART << 3) | \
>   				 SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_AUTOIDLE)
> -
> +#define DMTIMER_TYPE1_DISABLE	(SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE)
>   #define DMTIMER_TYPE2_ENABLE	(SYSC_IDLE_SMART_WKUP << 2)
>   #define DMTIMER_RESET_WAIT	100000
>   
> @@ -44,6 +44,8 @@ struct dmtimer_systimer {
>   	u8 ctrl;
>   	u8 wakeup;
>   	u8 ifctrl;
> +	struct clk *fck;
> +	struct clk *ick;
>   	unsigned long rate;
>   };
>   
> @@ -298,16 +300,20 @@ static void __init dmtimer_systimer_select_best(void)
>   }
>   
>   /* Interface clocks are only available on some SoCs variants */
> -static int __init dmtimer_systimer_init_clock(struct device_node *np,
> +static int __init dmtimer_systimer_init_clock(struct dmtimer_systimer *t,
> +					      struct device_node *np,
>   					      const char *name,
>   					      unsigned long *rate)
>   {
>   	struct clk *clock;
>   	unsigned long r;
> +	bool is_ick = false;
>   	int error;
>   
> +	is_ick = !strncmp(name, "ick", 3);
> +
>   	clock = of_clk_get_by_name(np, name);
> -	if ((PTR_ERR(clock) == -EINVAL) && !strncmp(name, "ick", 3))
> +	if ((PTR_ERR(clock) == -EINVAL) && is_ick)
>   		return 0;
>   	else if (IS_ERR(clock))
>   		return PTR_ERR(clock);
> @@ -320,6 +326,11 @@ static int __init dmtimer_systimer_init_clock(struct device_node *np,
>   	if (!r)
>   		return -ENODEV;
>   
> +	if (is_ick)
> +		t->ick = clock;
> +	else
> +		t->fck = clock;
> +
>   	*rate = r;
>   
>   	return 0;
> @@ -339,7 +350,10 @@ static void dmtimer_systimer_enable(struct dmtimer_systimer *t)
>   
>   static void dmtimer_systimer_disable(struct dmtimer_systimer *t)
>   {
> -	writel_relaxed(0, t->base + t->sysc);
> +	if (!dmtimer_systimer_revision1(t))
> +		return;
> +
> +	writel_relaxed(DMTIMER_TYPE1_DISABLE, t->base + t->sysc);
>   }
>   
>   static int __init dmtimer_systimer_setup(struct device_node *np,
> @@ -366,13 +380,13 @@ static int __init dmtimer_systimer_setup(struct device_node *np,
>   		pr_err("%s: clock source init failed: %i\n", __func__, error);
>   
>   	/* For ti-sysc, we have timer clocks at the parent module level */
> -	error = dmtimer_systimer_init_clock(np->parent, "fck", &rate);
> +	error = dmtimer_systimer_init_clock(t, np->parent, "fck", &rate);
>   	if (error)
>   		goto err_unmap;
>   
>   	t->rate = rate;
>   
> -	error = dmtimer_systimer_init_clock(np->parent, "ick", &rate);
> +	error = dmtimer_systimer_init_clock(t, np->parent, "ick", &rate);
>   	if (error)
>   		goto err_unmap;
>   
> @@ -496,12 +510,18 @@ static void omap_clockevent_idle(struct clock_event_device *evt)
>   	struct dmtimer_systimer *t = &clkevt->t;
>   
>   	dmtimer_systimer_disable(t);
> +	clk_disable(t->fck);
>   }
>   
>   static void omap_clockevent_unidle(struct clock_event_device *evt)
>   {
>   	struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt);
>   	struct dmtimer_systimer *t = &clkevt->t;
> +	int error;
> +
> +	error = clk_enable(t->fck);
> +	if (error)
> +		pr_err("could not enable timer fck on resume: %i\n", error);
>   
>   	dmtimer_systimer_enable(t);
>   	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena);
> @@ -570,8 +590,8 @@ static int __init dmtimer_clockevent_init(struct device_node *np)
>   					3, /* Timer internal resynch latency */
>   					0xffffffff);
>   
> -	if (of_device_is_compatible(np, "ti,am33xx") ||
> -	    of_device_is_compatible(np, "ti,am43")) {
> +	if (of_machine_is_compatible("ti,am33xx") ||
> +	    of_machine_is_compatible("ti,am43")) {
>   		dev->suspend = omap_clockevent_idle;
>   		dev->resume = omap_clockevent_unidle;
>   	}
> @@ -616,12 +636,18 @@ static void dmtimer_clocksource_suspend(struct clocksource *cs)
>   
>   	clksrc->loadval = readl_relaxed(t->base + t->counter);
>   	dmtimer_systimer_disable(t);
> +	clk_disable(t->fck);
>   }
>   
>   static void dmtimer_clocksource_resume(struct clocksource *cs)
>   {
>   	struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs);
>   	struct dmtimer_systimer *t = &clksrc->t;
> +	int error;
> +
> +	error = clk_enable(t->fck);
> +	if (error)
> +		pr_err("could not enable timer fck on resume: %i\n", error);
>   
>   	dmtimer_systimer_enable(t);
>   	writel_relaxed(clksrc->loadval, t->base + t->counter);
> @@ -653,8 +679,8 @@ static int __init dmtimer_clocksource_init(struct device_node *np)
>   	dev->mask = CLOCKSOURCE_MASK(32);
>   	dev->flags = CLOCK_SOURCE_IS_CONTINUOUS;
>   
> -	if (of_device_is_compatible(np, "ti,am33xx") ||
> -	    of_device_is_compatible(np, "ti,am43")) {
> +	/* Unlike for clockevent, legacy code sets suspend only for am4 */
> +	if (of_machine_is_compatible("ti,am43")) {
>   		dev->suspend = dmtimer_clocksource_suspend;
>   		dev->resume = dmtimer_clocksource_resume;
>   	}
> 

It might be better to use SOC_BUS infra here, which is available on OMAP platforms by default,
instead if DT. What do you think?

-- 
Best regards,
grygorii

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2020-07-15 10:18 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-07-13 16:26 [PATCH] clocksource/drivers/timer-ti-dm: Fix suspend and resume for am3 and am4 Tony Lindgren
2020-07-13 16:26 ` Tony Lindgren
2020-07-15 10:17 ` Grygorii Strashko [this message]
2020-07-15 10:17   ` Grygorii Strashko
2020-07-15 17:32   ` Tony Lindgren
2020-07-15 17:32     ` Tony Lindgren
2020-07-15 18:43     ` Grygorii Strashko
2020-07-15 18:43       ` Grygorii Strashko
2020-07-17 10:29 ` Daniel Lezcano
2020-07-17 10:29   ` Daniel Lezcano
     [not found]   ` <f96cb9d8-c940-672a-b1d2-a26570d6f775@ti.com>
2020-07-20 13:56     ` Carlos Hernandez
2020-07-20 13:56       ` Carlos Hernandez
2020-07-20 14:30     ` Tony Lindgren
2020-07-20 14:30       ` Tony Lindgren
2020-07-21  3:35       ` Sekhar Nori
2020-07-21  3:35         ` Sekhar Nori
2020-07-21 13:11   ` Carlos Hernandez
2020-07-21 13:11     ` Carlos Hernandez
2020-07-21 13:49     ` Daniel Lezcano
2020-07-21 13:49       ` Daniel Lezcano
2020-07-21 16:15 ` [tip: timers/urgent] " tip-bot2 for Tony Lindgren

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1972bace-e9d1-b901-eb33-b4081a4b175d@ti.com \
    --to=grygorii.strashko@ti.com \
    --cc=ceh@ti.com \
    --cc=daniel.lezcano@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=tglx@linutronix.de \
    --cc=tony@atomide.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.