All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>
To: Dmitry Osipenko <digetx@gmail.com>
Cc: Thierry Reding <thierry.reding@gmail.com>,
	Lee Jones <lee.jones@linaro.org>,
	Jonathan Hunter <jonathanh@nvidia.com>,
	Svyatoslav Ryhel <clamor95@gmail.com>,
	Maxim Schwalm <maxim.schwalm@gmail.com>,
	linux-tegra@vger.kernel.org, linux-pwm@vger.kernel.org,
	kernel@pengutronix.de
Subject: Re: [PATCH v2] pwm: tegra: Optimize period calculation
Date: Mon, 15 Aug 2022 09:09:35 +0200	[thread overview]
Message-ID: <20220815070935.guqzzlny7f6kcprc@pengutronix.de> (raw)
In-Reply-To: <524ca143-e9d4-2a79-3e9e-c8b9ffc9f513@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 5340 bytes --]

On Mon, Aug 15, 2022 at 03:28:25AM +0300, Dmitry Osipenko wrote:
> Hi,
> 
> 25.04.2022 16:22, Uwe Kleine-König пишет:
> > Dividing by the result of a division looses precision because the result is
> > rounded twice. E.g. with clk_rate = 48000000 and period = 32760033 the
> > following numbers result:
> > 
> > 	rate = pc->clk_rate >> PWM_DUTY_WIDTH = 187500
> > 	hz = DIV_ROUND_CLOSEST_ULL(100ULL * NSEC_PER_SEC, period_ns) = 3052
> > 	rate = DIV_ROUND_CLOSEST_ULL(100ULL * rate, hz) = 6144
> > 
> > The exact result would be 6142.5061875 and (apart from rounding) this is
> > found by using a single division. As a side effect is also a tad
> > cheaper to calculate.
> > 
> > Also using clk_rate >> PWM_DUTY_WIDTH looses precision. Consider for
> > example clk_rate = 47999999 and period = 106667:
> > 
> > 	mul_u64_u64_div_u64(pc->clk_rate >> PWM_DUTY_WIDTH, period_ns,
> > 			    NSEC_PER_SEC) = 19
> > 
> > 	mul_u64_u64_div_u64(pc->clk_rate, period_ns,
> > 			    NSEC_PER_SEC << PWM_DUTY_WIDTH) = 20
> > 
> > (The exact result is 20.000062083332033.)
> > 
> > With this optimizations also switch from round-closest to round-down for
> > the period calculation. Given that the calculations were non-optimal for
> > quite some time now with variations in both directions which nobody
> > reported as a problem, this is the opportunity to align the driver's
> > behavior to the requirements of new drivers. This has several upsides:
> > 
> >  - Implementation is easier as there are no round-nearest variants of
> >    mul_u64_u64_div_u64().
> >  - Requests for too small periods are now consistently refused. This was
> >    kind of arbitrary before, where period_ns < min_period_ns was
> >    refused, but in some cases min_period_ns isn't actually implementable
> >    and then values between min_period_ns and the actual minimum were
> >    rounded up to the actual minimum.
> > 
> > Note that the duty_cycle calculation isn't using the usual round-down
> > approach yet.
> > 
> > Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> > ---
> > Hello,
> > 
> > changes since (implicit) v1: Updated changelog to explain why rate = 0
> > is refused now.
> > 
> > Best regards
> > Uwe
> > 
> >  drivers/pwm/pwm-tegra.c | 10 +++++-----
> >  1 file changed, 5 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
> > index e5a9ffef4a71..7fc03a9ec154 100644
> > --- a/drivers/pwm/pwm-tegra.c
> > +++ b/drivers/pwm/pwm-tegra.c
> > @@ -99,7 +99,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> >  			    int duty_ns, int period_ns)
> >  {
> >  	struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
> > -	unsigned long long c = duty_ns, hz;
> > +	unsigned long long c = duty_ns;
> >  	unsigned long rate, required_clk_rate;
> >  	u32 val = 0;
> >  	int err;
> > @@ -156,11 +156,9 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> >  		pc->clk_rate = clk_get_rate(pc->clk);
> >  	}
> >  
> > -	rate = pc->clk_rate >> PWM_DUTY_WIDTH;
> > -
> >  	/* Consider precision in PWM_SCALE_WIDTH rate calculation */
> > -	hz = DIV_ROUND_CLOSEST_ULL(100ULL * NSEC_PER_SEC, period_ns);
> > -	rate = DIV_ROUND_CLOSEST_ULL(100ULL * rate, hz);
> > +	rate = mul_u64_u64_div_u64(pc->clk_rate, period_ns,
> > +				   (u64)NSEC_PER_SEC << PWM_DUTY_WIDTH);
> >  
> >  	/*
> >  	 * Since the actual PWM divider is the register's frequency divider
> > @@ -169,6 +167,8 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
> >  	 */
> >  	if (rate > 0)
> >  		rate--;
> > +	else
> > +		return -EINVAL;
> 
> This patch broke backlight on Asus Transformer tablets, they are now
> getting this -EINVAL. The root of the problem is under investigation.

This means that you requested a period that is smaller than the minimal
period the hardware can implement.

What is the clk rate of the PWM clk (i.e. pc->clk_rate?). Looking at
arch/arm/boot/dts/tegra30-asus-transformer-common.dtsi I guess period is
4000000. That in turn would mean that

	mul_u64_u64_div_u64(pc->clk_rate, period_ns, (u64)NSEC_PER_SEC << PWM_DUTY_WIDTH)

returned 0 which (with the assumption period_ns = 4000000) would imply
the clk rate is less than 64000.

I don't know the machine, but some more information would be good: What
is the actual clock rate? Can you please enable PWM_DEBUG (at compile
time) and tracing (at runtime) (i.e.

	echo 1 > /sys/kernel/debug/tracing/events/pwm/enable

), reproduce the problem and provide the trace (i.e.

	cat /sys/kernel/debug/tracing/trace

)?

> Should we revert this patch meantime or maybe you (Uwe/Thierry) have an
> idea about what actually has gone wrong here? Thanks in advance.

I'd like to understand if the problem is indeed that the backlight
driver requests a too small period. In this case I'd prefer to adapt the
backlight device to use better pwm settings. If there is a problem in
my change, this needs to be fixed. If you provide the above data, I can
check the details.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

  reply	other threads:[~2022-08-15  7:09 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-25 13:22 [PATCH v2] pwm: tegra: Optimize period calculation Uwe Kleine-König
2022-05-20 14:20 ` Thierry Reding
2022-08-15  0:28 ` Dmitry Osipenko
2022-08-15  7:09   ` Uwe Kleine-König [this message]
2022-08-18  7:54     ` Uwe Kleine-König
2022-08-18 20:34       ` Dmitry Osipenko
2022-09-21  8:17         ` Uwe Kleine-König
2022-09-22 11:12           ` Jon Hunter
2022-09-23 12:10             ` Thierry Reding
2022-10-04 10:28               ` Thomas Graichen
2022-10-04 10:41                 ` Uwe Kleine-König
     [not found]   ` <CAPVz0n1Xy=feSqw7_bvNw17=xVGnk2yhAMFmyfddU128dU+5qQ@mail.gmail.com>
2022-09-21 13:32     ` Uwe Kleine-König
     [not found]       ` <CAPVz0n19V5Lx889GO7wRzuvPAdBeVE8vXsMzQ-6EGyp4DFGD5w@mail.gmail.com>
2022-09-21 17:09         ` Uwe Kleine-König
2022-10-25 14:22 ` Jon Hunter
2022-10-26  0:10   ` Uwe Kleine-König
2022-10-26 10:14     ` Jon Hunter

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=20220815070935.guqzzlny7f6kcprc@pengutronix.de \
    --to=u.kleine-koenig@pengutronix.de \
    --cc=clamor95@gmail.com \
    --cc=digetx@gmail.com \
    --cc=jonathanh@nvidia.com \
    --cc=kernel@pengutronix.de \
    --cc=lee.jones@linaro.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=maxim.schwalm@gmail.com \
    --cc=thierry.reding@gmail.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.