diff mbox series

[5/5] pwm: stm32: Fix enable count for clk in .probe()

Message ID 20231019200658.1754190-12-u.kleine-koenig@pengutronix.de
State Accepted
Delegated to: Uwe Kleine-König
Headers show
Series pwm: stm32: Cleanups, get_state() and proper hw take over | expand

Commit Message

Uwe Kleine-König Oct. 19, 2023, 8:07 p.m. UTC
From: Philipp Zabel <p.zabel@pengutronix.de>

Make the driver take over hardware state without disabling in .probe()
and enable the clock for each enabled channel.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
[ukleinek: split off from a patch that also implemented .get_state()]
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-stm32.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

Comments

Fabrice Gasnier Nov. 14, 2023, 1:35 p.m. UTC | #1
On 10/19/23 22:07, Uwe Kleine-König wrote:
> From: Philipp Zabel <p.zabel@pengutronix.de>
> 
> Make the driver take over hardware state without disabling in .probe()
> and enable the clock for each enabled channel.
> 
> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> [ukleinek: split off from a patch that also implemented .get_state()]
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> ---
>  drivers/pwm/pwm-stm32.c | 18 ++++++++++++++----
>  1 file changed, 14 insertions(+), 4 deletions(-)


Hi Uwe,

I'd only have a suggestion on the commit title:
pwm: stm32: Fix enable count for clk in .probe()
            ^
On first sight, the "Fix" may suggest that this fixes something older in
the tree. This would suggest a Fixes tag which isn't the case in this
series, as this is a split of the .get_state() patch.
Is it possible to rephrase ?
something like: set clk enable count when probing channels ?

Apart from that, you can add my:
Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>

---
I've additional questions, unrelated to this patch. I had a look at
pwm-stm32-lp.c, the clock enabling is done directly in the .get_state()
routine. I think this should be moved to the .probe() routine as done
here. There's likely a risk, that clk enable count gets increased
artificially, at least since commit cfc4c189bc70 "pwm: Read initial
hardware state at request time".
Shall I send a patch for pwm-stm32-lp.c, similar as this patch ? Or has
it been spotted already ?

Best Regards,
Thanks,
Fabrice

> 
> diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
> index 68239567a564..97a2c3c09b69 100644
> --- a/drivers/pwm/pwm-stm32.c
> +++ b/drivers/pwm/pwm-stm32.c
> @@ -605,17 +605,21 @@ static void stm32_pwm_detect_complementary(struct stm32_pwm *priv)
>  	priv->have_complementary_output = (ccer != 0);
>  }
>  
> -static unsigned int stm32_pwm_detect_channels(struct stm32_pwm *priv)
> +static unsigned int stm32_pwm_detect_channels(struct stm32_pwm *priv,
> +					      unsigned int *num_enabled)
>  {
> -	u32 ccer;
> +	u32 ccer, ccer_backup;
>  
>  	/*
>  	 * If channels enable bits don't exist writing 1 will have no
>  	 * effect so we can detect and count them.
>  	 */
> +	regmap_read(priv->regmap, TIM_CCER, &ccer_backup);
>  	regmap_set_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE);
>  	regmap_read(priv->regmap, TIM_CCER, &ccer);
> -	regmap_clear_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE);
> +	regmap_write(priv->regmap, TIM_CCER, ccer_backup);
> +
> +	*num_enabled = hweight32(ccer_backup & TIM_CCER_CCXE);
>  
>  	return hweight32(ccer & TIM_CCER_CCXE);
>  }
> @@ -626,6 +630,8 @@ static int stm32_pwm_probe(struct platform_device *pdev)
>  	struct device_node *np = dev->of_node;
>  	struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent);
>  	struct stm32_pwm *priv;
> +	unsigned int num_enabled;
> +	unsigned int i;
>  	int ret;
>  
>  	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> @@ -648,7 +654,11 @@ static int stm32_pwm_probe(struct platform_device *pdev)
>  
>  	priv->chip.dev = dev;
>  	priv->chip.ops = &stm32pwm_ops;
> -	priv->chip.npwm = stm32_pwm_detect_channels(priv);
> +	priv->chip.npwm = stm32_pwm_detect_channels(priv, &num_enabled);
> +
> +	/* Initialize clock refcount to number of enabled PWM channels. */
> +	for (i = 0; i < num_enabled; i++)
> +		clk_enable(priv->clk);
>  
>  	ret = devm_pwmchip_add(dev, &priv->chip);
>  	if (ret < 0)
Uwe Kleine-König Nov. 14, 2023, 9:20 p.m. UTC | #2
On Tue, Nov 14, 2023 at 02:35:19PM +0100, Fabrice Gasnier wrote:
> On 10/19/23 22:07, Uwe Kleine-König wrote:
> > From: Philipp Zabel <p.zabel@pengutronix.de>
> > 
> > Make the driver take over hardware state without disabling in .probe()
> > and enable the clock for each enabled channel.
> > 
> > Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> > [ukleinek: split off from a patch that also implemented .get_state()]
> > Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> > ---
> >  drivers/pwm/pwm-stm32.c | 18 ++++++++++++++----
> >  1 file changed, 14 insertions(+), 4 deletions(-)
> 
> 
> Hi Uwe,
> 
> I'd only have a suggestion on the commit title:
> pwm: stm32: Fix enable count for clk in .probe()
>             ^
> On first sight, the "Fix" may suggest that this fixes something older in
> the tree. This would suggest a Fixes tag which isn't the case in this
> series, as this is a split of the .get_state() patch.
> Is it possible to rephrase ?

IMHO it is a fix, the hw state wasn't properly taken over before.
If you want a Fixes line, that's:

Fixes: 7edf7369205b ("pwm: Add driver for STM32 plaftorm")

> something like: set clk enable count when probing channels ?
> 
> Apart from that, you can add my:
> Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
> 
> ---
> I've additional questions, unrelated to this patch. I had a look at
> pwm-stm32-lp.c, the clock enabling is done directly in the .get_state()
> routine. I think this should be moved to the .probe() routine as done
> here. There's likely a risk, that clk enable count gets increased
> artificially, at least since commit cfc4c189bc70 "pwm: Read initial
> hardware state at request time".
> Shall I send a patch for pwm-stm32-lp.c, similar as this patch ? Or has
> it been spotted already ?

I'm not aware of someone working on stm32-lp, so feel free to prepare a
patch!

Best regards and thanks for your review,
Uwe
Fabrice Gasnier Nov. 15, 2023, 9:02 a.m. UTC | #3
On 11/14/23 22:20, Uwe Kleine-König wrote:
> On Tue, Nov 14, 2023 at 02:35:19PM +0100, Fabrice Gasnier wrote:
>> On 10/19/23 22:07, Uwe Kleine-König wrote:
>>> From: Philipp Zabel <p.zabel@pengutronix.de>
>>>
>>> Make the driver take over hardware state without disabling in .probe()
>>> and enable the clock for each enabled channel.
>>>
>>> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
>>> [ukleinek: split off from a patch that also implemented .get_state()]
>>> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
>>> ---
>>>  drivers/pwm/pwm-stm32.c | 18 ++++++++++++++----
>>>  1 file changed, 14 insertions(+), 4 deletions(-)
>>
>>
>> Hi Uwe,
>>
>> I'd only have a suggestion on the commit title:
>> pwm: stm32: Fix enable count for clk in .probe()
>>             ^
>> On first sight, the "Fix" may suggest that this fixes something older in
>> the tree. This would suggest a Fixes tag which isn't the case in this
>> series, as this is a split of the .get_state() patch.
>> Is it possible to rephrase ?
> 
> IMHO it is a fix, the hw state wasn't properly taken over before.

Hi Uwe,

Indeed, the HW state wasn't taken. Instead the driver used to be
forcibly stop each channel: regmap_clear_bits(priv->regmap, TIM_CCER,
TIM_CCER_CCXE);
So the clk enable count (of 0) reflects this. That's kind of consistent
state.

> If you want a Fixes line, that's:
> 
> Fixes: 7edf7369205b ("pwm: Add driver for STM32 plaftorm")

Well, the original driver didn't implement the .get_state.
BUT, more thinking about this, I think it lacks to read the global
enable status of the timer, e.g. TIM_CR1_CEN.

Original driver stops each channel (clear CCXE), but after probing, the
global TIM_CR1_CEN bit may remains 1 (from bootloader), without a
running clock.

If we're talking about fixing the original driver (probably unrelevant
without a working .get_state), then I think this part is missing.

(with or without a Fixes tag) Could you add a check on global counter
enable bit (TIM_CR1_CEN) both in the .get_state(), and in the
stm32_pwm_detect_channels(), that counts the num_enabled channels ?

In case the TIM_CR1_CEN isn't set (but some of the TIM_CCER_CCXE are),
the driver will report enabled channels. But physically, the pwm output
will be inactive.
That's more a robustness case... depending on what's been done possibly
by bootloader. What to you think ?

> 
>> something like: set clk enable count when probing channels ?
>>
>> Apart from that, you can add my:
>> Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
>>
>> ---
>> I've additional questions, unrelated to this patch. I had a look at
>> pwm-stm32-lp.c, the clock enabling is done directly in the .get_state()
>> routine. I think this should be moved to the .probe() routine as done
>> here. There's likely a risk, that clk enable count gets increased
>> artificially, at least since commit cfc4c189bc70 "pwm: Read initial
>> hardware state at request time".
>> Shall I send a patch for pwm-stm32-lp.c, similar as this patch ? Or has
>> it been spotted already ?
> 
> I'm not aware of someone working on stm32-lp, so feel free to prepare a
> patch!

Ok thanks! Will look into it.
Best Regards,
Fabrice

> 
> Best regards and thanks for your review,
> Uwe
>
Uwe Kleine-König Nov. 15, 2023, 9:01 p.m. UTC | #4
Hello Fabrice,

On Wed, Nov 15, 2023 at 10:02:20AM +0100, Fabrice Gasnier wrote:
> (with or without a Fixes tag) Could you add a check on global counter
> enable bit (TIM_CR1_CEN) both in the .get_state(), and in the
> stm32_pwm_detect_channels(), that counts the num_enabled channels ?

I'd address that separately, mostly because the patches forwarded here
are not mine.

> In case the TIM_CR1_CEN isn't set (but some of the TIM_CCER_CCXE are),
> the driver will report enabled channels. But physically, the pwm output
> will be inactive.

Huuu, that means if channel #0 is running and I start a capture on
channel #1 which results in unconditionally calling
regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); (in
stm32_pwm_raw_capture()) channel #0 stops to toggle!

> That's more a robustness case... depending on what's been done possibly
> by bootloader. What to you think ?

I would assume that a bootloader that sets the CCXE bits also enables
TIM_CR1_CEN and so in practise Philipp's patch is fine. But I agree that
doing things properly would be better.

Best regards
Uwe
Fabrice Gasnier Nov. 16, 2023, 3:05 p.m. UTC | #5
On 11/15/23 22:01, Uwe Kleine-König wrote:
> Hello Fabrice,
> 
> On Wed, Nov 15, 2023 at 10:02:20AM +0100, Fabrice Gasnier wrote:
>> (with or without a Fixes tag) Could you add a check on global counter
>> enable bit (TIM_CR1_CEN) both in the .get_state(), and in the
>> stm32_pwm_detect_channels(), that counts the num_enabled channels ?
> 
> I'd address that separately, mostly because the patches forwarded here
> are not mine.

Ok, let's go this way.

> 
>> In case the TIM_CR1_CEN isn't set (but some of the TIM_CCER_CCXE are),
>> the driver will report enabled channels. But physically, the pwm output
>> will be inactive.
> 
> Huuu, that means if channel #0 is running and I start a capture on
> channel #1 which results in unconditionally calling
> regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); (in
> stm32_pwm_raw_capture()) channel #0 stops to toggle!

Basically no, please find my answers sent separately on "[PATCH] pwm:
stm32: Mark capture support as broken"

> 
>> That's more a robustness case... depending on what's been done possibly
>> by bootloader. What to you think ?
> 
> I would assume that a bootloader that sets the CCXE bits also enables
> TIM_CR1_CEN and so in practise Philipp's patch is fine. But I agree that
> doing things properly would be better.

ok, thanks,
Best Regards,
Fabrice
> 
> Best regards
> Uwe
>
diff mbox series

Patch

diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index 68239567a564..97a2c3c09b69 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -605,17 +605,21 @@  static void stm32_pwm_detect_complementary(struct stm32_pwm *priv)
 	priv->have_complementary_output = (ccer != 0);
 }
 
-static unsigned int stm32_pwm_detect_channels(struct stm32_pwm *priv)
+static unsigned int stm32_pwm_detect_channels(struct stm32_pwm *priv,
+					      unsigned int *num_enabled)
 {
-	u32 ccer;
+	u32 ccer, ccer_backup;
 
 	/*
 	 * If channels enable bits don't exist writing 1 will have no
 	 * effect so we can detect and count them.
 	 */
+	regmap_read(priv->regmap, TIM_CCER, &ccer_backup);
 	regmap_set_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE);
 	regmap_read(priv->regmap, TIM_CCER, &ccer);
-	regmap_clear_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE);
+	regmap_write(priv->regmap, TIM_CCER, ccer_backup);
+
+	*num_enabled = hweight32(ccer_backup & TIM_CCER_CCXE);
 
 	return hweight32(ccer & TIM_CCER_CCXE);
 }
@@ -626,6 +630,8 @@  static int stm32_pwm_probe(struct platform_device *pdev)
 	struct device_node *np = dev->of_node;
 	struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent);
 	struct stm32_pwm *priv;
+	unsigned int num_enabled;
+	unsigned int i;
 	int ret;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -648,7 +654,11 @@  static int stm32_pwm_probe(struct platform_device *pdev)
 
 	priv->chip.dev = dev;
 	priv->chip.ops = &stm32pwm_ops;
-	priv->chip.npwm = stm32_pwm_detect_channels(priv);
+	priv->chip.npwm = stm32_pwm_detect_channels(priv, &num_enabled);
+
+	/* Initialize clock refcount to number of enabled PWM channels. */
+	for (i = 0; i < num_enabled; i++)
+		clk_enable(priv->clk);
 
 	ret = devm_pwmchip_add(dev, &priv->chip);
 	if (ret < 0)