RE: [PATCH v5 2/4] pwm: Add support for RZ/V2M PWM driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Uwe,

Thanks for your reply!

> From: Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxxxx>
> Sent: Wednesday, October 4, 2023 3:15 PM
> Subject: Re: [PATCH v5 2/4] pwm: Add support for RZ/V2M PWM driver
> 
> Hello Fabrizio,
> 
> On Tue, Oct 03, 2023 at 09:19:41PM +0000, Fabrizio Castro wrote:
> > > > +	if (period)
> > > > +		period += 1;
> > >
> > > This looks bogus, why don't you add 1 if RZV2M_PWMCYC is 0?
> >
> > Agreed. We should always add 1.
> >
> > > Also it suggests that the hardware cannot do a 100% relative duty
> > > cycle?
> >
> > It does support 100% duty cycle.
> > PWMCYC = 0 actually means 1 clock cycle, that's why the faff with
> > increment and decrement operations, and that's why the confusion.
> 
> So it doesn't support a 0% relative duty cycle?

It does support 0% duty cycle.

> 
> > > If I didn't miss anything here, please add that to the list of
> > > Limitations above.
> >
> > Thankfully not a limitation.
> >
> > >
> > > > +	state->period = DIV_ROUND_UP_ULL(NSEC_PER_SEC * (u64)period
> << (4
> > > * prescale),
> > > > +					 rzv2m_pwm->rate);
> > >
> > > The multiplication can overflow. I see no easy way to prevent this
> > > without introducing a mul_u64_u64_div_roundup helper. Maybe I miss
> > > something?
> >
> > It does overflow, good catch!
> > I think we could split this in three operations for now, and maybe
> > improve it later on:
> > period = NSEC_PER_SEC * (cyc + 1);
> > period = DIV64_U64_ROUND_UP(period, rzv2m_pwm->rate);
> > period <<= rzv2m_pwm_prescale_to_shift(prescale);
> 
> You're loosing precision here though. With /^ = div_round_up:
> 
> 	1000000000 * 5 /^ 3 << 2 == 6666666668
> 	1000000000 * 5 << 2 /^ 3 == 6666666667

Yep.

> 
> So I correct my statement to: I see no easy and exact way to prevent
> an
> overflow without introducing a mul_u64_u64_div_roundup helper. :-)

Indeed. In my mind, the best way to tackle this problem is for such an
API to use an internal representation of 128-bit, so that it can calculate
(a*b + c - 1)/c accurately, and return both the high and low part of the
128-bit result (and maybe keeping the high part result optional?).
Something like
u64 mul_u64_u64_div_u64_roundup(u64 a, u64 b, u64 c, u64 *res_high);
or
void mul_u64_u64_div_u64_roundup(u64 a, u64 b, u64 c, u64 *res_high, u64 *res_low);

Needless to say, the API may take quite some time to perform the calculations,
but if precision/accuracy is what we need, there is probably no better
way of addressing this, unless you have a better idea?

Looking around, my understanding is that other drivers may benefit from
this sort of accurate rounded up result when a, b, and c are 64-bit, is that
why you think it has come the time to address this, or do you think this
is the first instance of such need?

Thanks,
Fab

> 
> > with rzv2m_pwm_prescale_to_shift as below:
> > static inline int rzv2m_pwm_prescale_to_shift(u8 prescale)
> > {
> >     return prescale == 3 ? 11 : prescale * 4;
> > }
> >
> > As it turns out "<< (4 * prescale)" and ">> (4 * prescale)" are not
> > correct for prescale == 3.
> > As per manual: PWMPS = 3 means a frequency division by 2048, and not
> > 4096.
> 
> funny hardware.
> 
> Best regards
> Uwe
> 
> --
> Pengutronix e.K.                           | Uwe Kleine-König
> |
> Industrial Linux Solutions                 |
> https://www.pengutronix.de/ |




[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux