[U-Boot] [PATCH 1/3] pwm: sunxi: fix off-by-one that prevented PWM to use prescaler bypass

Fix off-by-one that prevented PWM driver to use prescaler bypass. Without this change prescaler is always enabled.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com --- drivers/pwm/sunxi_pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pwm/sunxi_pwm.c b/drivers/pwm/sunxi_pwm.c index 3c7dffdd90..baee503730 100644 --- a/drivers/pwm/sunxi_pwm.c +++ b/drivers/pwm/sunxi_pwm.c @@ -74,7 +74,7 @@ static int sunxi_pwm_set_config(struct udevice *dev, uint channel,
debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
- for (prescaler = 0; prescaler < SUNXI_PWM_CTRL_PRESCALE0_MASK; + for (prescaler = 0; prescaler <= SUNXI_PWM_CTRL_PRESCALE0_MASK; prescaler++) { if (!prescaler_table[prescaler]) continue;

Looks like old prescaler was used when configuring PWM, fix it.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com --- drivers/pwm/sunxi_pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pwm/sunxi_pwm.c b/drivers/pwm/sunxi_pwm.c index baee503730..6284409b4f 100644 --- a/drivers/pwm/sunxi_pwm.c +++ b/drivers/pwm/sunxi_pwm.c @@ -97,7 +97,7 @@ static int sunxi_pwm_set_config(struct udevice *dev, uint channel, v &= ~SUNXI_PWM_CTRL_CLK_GATE; writel(v, ®s->ctrl); v &= ~SUNXI_PWM_CTRL_PRESCALE0_MASK; - v |= (priv->prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK); + v |= (prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK); writel(v, ®s->ctrl); v |= SUNXI_PWM_CTRL_CLK_GATE; writel(v, ®s->ctrl);

Choose best prescaler to improve PWM resolution. Without this change driver chooses first prescaler that gives us period value within range, but it could be not the best one.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com --- drivers/pwm/sunxi_pwm.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/drivers/pwm/sunxi_pwm.c b/drivers/pwm/sunxi_pwm.c index 6284409b4f..8a55e4f461 100644 --- a/drivers/pwm/sunxi_pwm.c +++ b/drivers/pwm/sunxi_pwm.c @@ -67,49 +67,55 @@ static int sunxi_pwm_set_config(struct udevice *dev, uint channel, { struct sunxi_pwm_priv *priv = dev_get_priv(dev); struct sunxi_pwm *regs = priv->regs; - int prescaler; - u32 v, period = 0, duty; - u64 scaled_freq = 0; + int best_prescaler = 0; + u32 v, best_period = 0, duty; + u64 best_scaled_freq = 0; const u32 nsecs_per_sec = 1000000000U;
debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
- for (prescaler = 0; prescaler <= SUNXI_PWM_CTRL_PRESCALE0_MASK; + for (int prescaler = 0; prescaler <= SUNXI_PWM_CTRL_PRESCALE0_MASK; prescaler++) { + u32 period = 0; + u64 scaled_freq = 0; if (!prescaler_table[prescaler]) continue; scaled_freq = lldiv(OSC_24MHZ, prescaler_table[prescaler]); period = lldiv(scaled_freq * period_ns, nsecs_per_sec); - if (period - 1 <= SUNXI_PWM_CH0_PERIOD_MAX) - break; + if ((period - 1 <= SUNXI_PWM_CH0_PERIOD_MAX) && + best_period < period) { + best_period = period; + best_scaled_freq = scaled_freq; + best_prescaler = prescaler; + } }
- if (period - 1 > SUNXI_PWM_CH0_PERIOD_MAX) { + if (best_period - 1 > SUNXI_PWM_CH0_PERIOD_MAX) { debug("%s: failed to find prescaler value\n", __func__); return -EINVAL; }
- duty = lldiv(scaled_freq * duty_ns, nsecs_per_sec); + duty = lldiv(best_scaled_freq * duty_ns, nsecs_per_sec);
- if (priv->prescaler != prescaler) { + if (priv->prescaler != best_prescaler) { /* Mask clock to update prescaler */ v = readl(®s->ctrl); v &= ~SUNXI_PWM_CTRL_CLK_GATE; writel(v, ®s->ctrl); v &= ~SUNXI_PWM_CTRL_PRESCALE0_MASK; - v |= (prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK); + v |= (best_prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK); writel(v, ®s->ctrl); v |= SUNXI_PWM_CTRL_CLK_GATE; writel(v, ®s->ctrl); - priv->prescaler = prescaler; + priv->prescaler = best_prescaler; }
- writel(SUNXI_PWM_CH0_PERIOD_PRD(period) | + writel(SUNXI_PWM_CH0_PERIOD_PRD(best_period) | SUNXI_PWM_CH0_PERIOD_DUTY(duty), ®s->ch0_period);
debug("%s: prescaler: %d, period: %d, duty: %d\n", __func__, priv->prescaler, - period, duty); + best_period, duty);
return 0; }

On 2018-10-16, Vasily Khoruzhick wrote:
Choose best prescaler to improve PWM resolution. Without this change driver chooses first prescaler that gives us period value within range, but it could be not the best one.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
Fixes LCD backlight issues with the pinebook series:
https://patchwork.ozlabs.org/project/uboot/list/?series=71358
Tested-by: Vagrant Cascadian vagrant@debian.org
drivers/pwm/sunxi_pwm.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/drivers/pwm/sunxi_pwm.c b/drivers/pwm/sunxi_pwm.c index 6284409b4f..8a55e4f461 100644 --- a/drivers/pwm/sunxi_pwm.c +++ b/drivers/pwm/sunxi_pwm.c @@ -67,49 +67,55 @@ static int sunxi_pwm_set_config(struct udevice *dev, uint channel, { struct sunxi_pwm_priv *priv = dev_get_priv(dev); struct sunxi_pwm *regs = priv->regs;
- int prescaler;
- u32 v, period = 0, duty;
- u64 scaled_freq = 0;
int best_prescaler = 0;
u32 v, best_period = 0, duty;
u64 best_scaled_freq = 0; const u32 nsecs_per_sec = 1000000000U;
debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
- for (prescaler = 0; prescaler <= SUNXI_PWM_CTRL_PRESCALE0_MASK;
- for (int prescaler = 0; prescaler <= SUNXI_PWM_CTRL_PRESCALE0_MASK; prescaler++) {
u32 period = 0;
if (!prescaler_table[prescaler]) continue; scaled_freq = lldiv(OSC_24MHZ, prescaler_table[prescaler]); period = lldiv(scaled_freq * period_ns, nsecs_per_sec);u64 scaled_freq = 0;
if (period - 1 <= SUNXI_PWM_CH0_PERIOD_MAX)
break;
if ((period - 1 <= SUNXI_PWM_CH0_PERIOD_MAX) &&
best_period < period) {
best_period = period;
best_scaled_freq = scaled_freq;
best_prescaler = prescaler;
}}
- if (period - 1 > SUNXI_PWM_CH0_PERIOD_MAX) {
- if (best_period - 1 > SUNXI_PWM_CH0_PERIOD_MAX) { debug("%s: failed to find prescaler value\n", __func__); return -EINVAL; }
- duty = lldiv(scaled_freq * duty_ns, nsecs_per_sec);
- duty = lldiv(best_scaled_freq * duty_ns, nsecs_per_sec);
- if (priv->prescaler != prescaler) {
- if (priv->prescaler != best_prescaler) { /* Mask clock to update prescaler */ v = readl(®s->ctrl); v &= ~SUNXI_PWM_CTRL_CLK_GATE; writel(v, ®s->ctrl); v &= ~SUNXI_PWM_CTRL_PRESCALE0_MASK;
v |= (prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK);
writel(v, ®s->ctrl); v |= SUNXI_PWM_CTRL_CLK_GATE; writel(v, ®s->ctrl);v |= (best_prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK);
priv->prescaler = prescaler;
}priv->prescaler = best_prescaler;
- writel(SUNXI_PWM_CH0_PERIOD_PRD(period) |
writel(SUNXI_PWM_CH0_PERIOD_PRD(best_period) | SUNXI_PWM_CH0_PERIOD_DUTY(duty), ®s->ch0_period);
debug("%s: prescaler: %d, period: %d, duty: %d\n", __func__, priv->prescaler,
period, duty);
best_period, duty);
return 0;
}

On Wed, Oct 17, 2018 at 10:28 AM Vasily Khoruzhick anarsoul@gmail.com wrote:
Choose best prescaler to improve PWM resolution. Without this change driver chooses first prescaler that gives us period value within range, but it could be not the best one.
This commit need to elaborate about the real issue, ie got fixed. Understand it has chosen best prescaler but why and how it.

On Mon, Oct 22, 2018 at 11:29 AM Jagan Teki jagan@amarulasolutions.com wrote:
On Wed, Oct 17, 2018 at 10:28 AM Vasily Khoruzhick anarsoul@gmail.com wrote:
Choose best prescaler to improve PWM resolution. Without this change driver chooses first prescaler that gives us period value within range, but it could be not the best one.
This commit need to elaborate about the real issue, ie got fixed. Understand it has chosen best prescaler but why and how it.
If PWM resolution is low then close backlight levels can result in the same PWM settings, i.e. 0% and 10% can be the same (and thus backlight remains powered off). Basically the patch does what comment says - it improves PWM resolution.

On Wed, Oct 17, 2018 at 10:28 AM Vasily Khoruzhick anarsoul@gmail.com wrote:
Choose best prescaler to improve PWM resolution. Without this change driver chooses first prescaler that gives us period value within range, but it could be not the best one.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
Applied to all to u-boot-sunxi/master

I think this series already went into Anatolij's u-boot-staging/agust@denx.de, please make sure that you don't introduce any conflicts.On Wed, Oct 24, 2018 at 9:28 AM Jagan Teki jagan@amarulasolutions.com wrote:
On Wed, Oct 17, 2018 at 10:28 AM Vasily Khoruzhick anarsoul@gmail.com wrote:
Choose best prescaler to improve PWM resolution. Without this change driver chooses first prescaler that gives us period value within range, but it could be not the best one.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
Applied to all to u-boot-sunxi/master

On Tue, Oct 16, 2018 at 09:56:33PM -0700, Vasily Khoruzhick wrote:
Fix off-by-one that prevented PWM driver to use prescaler bypass. Without this change prescaler is always enabled.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
For the whole series, Acked-by: Maxime Ripard maxime.ripard@bootlin.com
Thanks! Maxime

On Tue, 16 Oct 2018 21:56:33 -0700 Vasily Khoruzhick anarsoul@gmail.com wrote:
Fix off-by-one that prevented PWM driver to use prescaler bypass. Without this change prescaler is always enabled.
Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
drivers/pwm/sunxi_pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Applied whole series to u-boot-staging/agust@denx.de, thanks!
-- Anatolij
participants (5)
-
Anatolij Gustschin
-
Jagan Teki
-
Maxime Ripard
-
Vagrant Cascadian
-
Vasily Khoruzhick