lkml.org 
[lkml]   [2021]   [Jun]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
From
SubjectRe: [PATCH v4 3/3] pwm: Add support for Xilinx AXI Timer
Date


On 6/27/21 2:19 PM, Uwe Kleine-König wrote:
> Hello Sean,
>
> On Fri, Jun 25, 2021 at 01:46:26PM -0400, Sean Anderson wrote:
>> On 6/25/21 12:56 PM, Uwe Kleine-König wrote:
>> > On Fri, Jun 25, 2021 at 11:13:33AM -0400, Sean Anderson wrote:
>> > > On 6/25/21 2:19 AM, Uwe Kleine-König wrote:
>> > > > On Fri, May 28, 2021 at 05:45:22PM -0400, Sean Anderson wrote:
>> > > >> + * - Cannot produce 100% duty cycle.
>> > > >
>> > > > Can it produce a 0% duty cycle? Below you're calling
>> > > > xilinx_timer_tlr_period(..., ..., ..., 0) then which returns -ERANGE.
>> > >
>> > > Yes. This is what you get when you try to specify 100% duty cycle (e.g.
>> > > TLR0 == TLR1).
>> >
>> > OK, so the hardware can do it, but your driver doesn't make use of it,
>> > right?
>>
>> So to clarify, I have observed the following behavior
>>
>> * When TCSR == 0, the output is constant low.
>> * When TLR1 (duty_cycle) >= TLR0 (period), the output is constant low.
>>
>> It might be possible to achieve constant high output by stopping the
>> counters during the high time, but leaving the PWM bit set. However, I
>> do not have a use case for this. I think it might be a nice follow-up
>> for someone who wants that feature.
>
> A typical use case is having an LED or a backlight connected to the PWM
> and and want it to be fully on.

I mean that I personally do not need this feature for my current
project, though I could see how someone might want this.

>
>> That being said, is there a standard way to specify 100% or 0% duty
>> cycle? It seems like one would have to detect these situations and use a
>> different code path.
>
> I don't understand that question. If pwm_apply_state is called with a
> state having .duty_cycle = 0 (and .enabled = true) you're supposed to
> emit a 0% relative duty. If .duty_cycle = .period is passed you're
> supposed to emit a 100% relative duty.

Ok.

>
>> > > >> + * - Only produces "normal" output.
>> > > >
>> > > > Does the output emit a low level when it's disabled?
>> > >
>> > > I believe so.
>> >
>> > Is there a possibility to be sure? I'd like to know that to complete my
>> > picture about the behaviour of the supported PWMs.
>>
>> See above.
>>
>> > > >> +static int xilinx_pwm_apply(struct pwm_chip *chip, struct pwm_device *unused,
>> > > >> + const struct pwm_state *state)
>> > > >> +{
>> > > >> + int ret;
>> > > >> + struct xilinx_timer_priv *priv = xilinx_pwm_chip_to_priv(chip);
>> > > >> + u32 tlr0, tlr1;
>> > > >> + u32 tcsr0 = xilinx_timer_read(priv, TCSR0);
>> > > >> + u32 tcsr1 = xilinx_timer_read(priv, TCSR1);
>> > > >> + bool enabled = xilinx_timer_pwm_enabled(tcsr0, tcsr1);
>> > > >> +
>> > > >> + if (state->polarity != PWM_POLARITY_NORMAL)
>> > > >> + return -EINVAL;
>> > > >> +
>> > > >> + ret = xilinx_timer_tlr_period(priv, &tlr0, tcsr0, state->period);
>> > > >> + if (ret)
>> > > >> + return ret;
>> > > >
>> > > > The implementation of xilinx_timer_tlr_period (in patch 2/3) returns
>> > > > -ERANGE for big periods. The good behaviour to implement is to cap to
>> > > > the biggest period possible in this case.
>> > >
>> > > Ok. Is this documented anywhere?
>> >
>> > I tried but Thierry didn't like the result and I didn't retry. The
>> > problem is also that many drivers we already have in the tree don't
>> > behave like this (because for a long time nobody cared). That new
>> > drivers should behave this way is my effort to get some consistent
>> > behaviour.
>>
>> Do you have a link to the thread? IMO if you would like to specify
>> behavior like this, is is very helpful to write it down so new authors
>> don't have to get to v4 before finding out about it ;)
>
> I misremembered, the last time I wanted to improve the documentation I
> didn't write anything about the policy with the goal to improve the
> documentation without hitting the a bit controversial policy stuff. The
> thread is available at
>
> https://lore.kernel.org/r/20191209213233.29574-2-u.kleine-koenig@pengutronix.de

This link does not work, but I was able to find the patch at

https://patchwork.ozlabs.org/project/linux-pwm/patch/20191209213233.29574-2-u.kleine-koenig@pengutronix.de/

However, it has no mention of rounding the rate, or what to do if a
given configuration cannot be applied.

> . Thierry didn't reply to this thread yet.

It seems the patch is marked as "Rejected" which is odd with no
feedback. Perhaps you should resend.

>
> My intension was to build on this one and formulate the expected policy
> for new drivers.
>
> The situation I'm in here wanting to install this policy is: On one hand
> Thierry argues that consumers don't care much about how .apply rounds
> because most consumers just don't have so exact requirements. And on the
> other hand he doesn't want to change the existing behaviour for already
> existing drivers to not break consumers. So the best I can currently to
> do work on a more consistent behaviour is to enforce this for new
> drivers.
>
>> > > And wouldn't this result in the wrong duty cycle? E.g. say the max
>> > > value is 100 and I try to apply a period of 150 and a duty_cycle of 75
>> > > (for a 50% duty cycle). If we cap at 100, then I will instead have a
>> > > 75% duty cycle, and there will be no error.
>> >
>> > Yes that is right. That there is no feedback is a problem that we have
>> > for a long time. I have a prototype patch that implements a
>> > pwm_round_state() function that lets a consumer know the result of
>> > applying a certain pwm_state in advance. But we're not there yet.
>>
>> So for the moment, why not give an error? This will be legal code both
>> now and after round_state is implemented.
>
> The problem is where to draw the line. To stay with your example: If a
> request for period = 150 ns comes in, and let X be the biggest period <=
> 150 ns that the hardware can configure. For which values of X should an
> error be returned and for which values the setting should be
> implemented.
>
> In my eyes the only sensible thing to implement here is to tell the
> consumer about X and let it decide if it's good enough. If you have a
> better idea let me hear about it.

Sure. And I think it's ok to tell the consumer that X is the best we can
do. But if they go along and request an unconfigurable state anyway, we
should tell them as much. IMO, this is the best way to prevent surprising
results in the API.

The real issue here is that it is impossible to determine the correct
way to round the PWM a priori, and in particular, without considering
both duty_cycle and period. If a consumer requests very small
period/duty cycle which we cannot produce, how should it be rounded?
Should we just set TLR0=1 and TLR1=0 to give them 66% duty cycle with
the least period? Or should we try and increase the period to better
approximate the % duty cycle? And both of these decisions must be made
knowing both parameters. We cannot (for example) just always round up,
since we may produce a configuration with TLR0 == TLR1, which would
produce 0% duty cycle instead of whatever was requested. Rounding rate
will introduce significant complexity into the driver. Most of the time
if a consumer requests an invalid rate, it is due to misconfiguration
which is best solved by fixing the configuration.

>> > > So I will silently get the wrong duty cycle, even when that duty cycle
>> > > is probably more important than the period.
>> >
>> > It depends on the use case and every policy is wrong for some cases. So
>> > I picked the policy I already explained because it is a) easy to
>> > implement for lowlevel drivers and b) it's easy to work with for
>> > consumers once we have pwm_round_state().
>>
>> What about sysfs? Right now if you try to specify an inexpressible
>> period you get an error message. I saw [1], but unfortunately there do
>> not appear to be any patches associated with it. Do you have plans to
>> implement such an interface?
>>
>> [1] https://lore.kernel.org/linux-pwm/CAO1O6seyi+1amAY5YLz0K1dkNd7ewAvot4K1eZMpAAQquz0-9g@mail.gmail.com/
>
> In my eyes we better implement a pwmctl interface that doesn't work via
> sysfs but using an ioctl; similar what gpio did with gpioctl for various
> reasons.
>
>> > > > Also note that state->period is an u64 but it is casted to unsigned int
>> > > > as this is the type of the forth parameter of xilinx_timer_tlr_period.
>> > >
>> > > Hm, it looks like I immediately cast period to a u64. I will change the
>> > > signature for this function next revision.
>> >
>> > Then note that period * clk_get_rate(priv->clk) might overflow.
>>
>> Ok, so is mult_frac the correct macro to use here?
>>
>> > > >> + ret = xilinx_timer_tlr_period(priv, &tlr1, tcsr1, state->duty_cycle);
>> > > >> + if (ret)
>> > > >> + return ret;
>>
>> Perhaps I should add
>>
>> if (tlr0 <= tlr1)
>> return -EINVAL;
>>
>> here to prevent accidentally getting 0% duty cycle.
>
> You can assume that duty_cycle <= period when .apply is called.

Ok, I will only check for == then.

--Sean

\
 
 \ /
  Last update: 2021-06-28 17:51    [W:0.098 / U:0.092 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site