Skip to contentSkip to conversation

pwm: sunxi: fix off-by-one that prevented PWM to use prescaler bypass

PATCH New Vasily Khoruzhick 5 participants 10 messages Oct 17, 2018 – Oct 24, 2018

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

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.

---
 drivers/pwm/sunxi_pwm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pwm/sunxi_pwm.c +1 -1
index 3c7dffdd90..baee503730 100644
@@ -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;
Signature · 1 line
2.19.0
#1 lore raw

PATCH 2/3 pwm: sunxi: use new prescaler when configuring PWM

Looks like old prescaler was used when configuring PWM, fix it.

---
 drivers/pwm/sunxi_pwm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pwm/sunxi_pwm.c +1 -1
index baee503730..6284409b4f 100644
@@ -97,7 +97,7 @@ static int sunxi_pwm_set_config(struct udevice *dev, uint channel,
 		v &= ~SUNXI_PWM_CTRL_CLK_GATE;
 		writel(v, &regs->ctrl);
 		v &= ~SUNXI_PWM_CTRL_PRESCALE0_MASK;
-		v |= (priv->prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK);
+		v |= (prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK);
 		writel(v, &regs->ctrl);
 		v |= SUNXI_PWM_CTRL_CLK_GATE;
 		writel(v, &regs->ctrl);
Signature · 1 line
2.19.0
#2 lore raw

PATCH 3/3 pwm: sunxi: choose best prescaler to improve PWM resolution

In reply to Vasily Khoruzhick

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.

---
 drivers/pwm/sunxi_pwm.c | 32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)
drivers/pwm/sunxi_pwm.c +19 -13
index 6284409b4f..8a55e4f461 100644
@@ -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(&regs->ctrl);
 		v &= ~SUNXI_PWM_CTRL_CLK_GATE;
 		writel(v, &regs->ctrl);
 		v &= ~SUNXI_PWM_CTRL_PRESCALE0_MASK;
-		v |= (prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK);
+		v |= (best_prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK);
 		writel(v, &regs->ctrl);
 		v |= SUNXI_PWM_CTRL_CLK_GATE;
 		writel(v, &regs->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), &regs->ch0_period);
 
 	debug("%s: prescaler: %d, period: %d, duty: %d\n",
 	      __func__, priv->prescaler,
-	      period, duty);
+	      best_period, duty);
 
 	return 0;
 }
Signature · 1 line
2.19.0
#3 lore raw

PATCH 3/3 pwm: sunxi: choose best prescaler to improve PWM resolution

Quoted 5 lines · Vasily Khoruzhick

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.

Fixes LCD backlight issues with the pinebook series:

https://patchwork.ozlabs.org/project/uboot/list/?series=71358

Quoted 67 lines
---
 drivers/pwm/sunxi_pwm.c | 32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)
drivers/pwm/sunxi_pwm.c +17 -12
index 6284409b4f..8a55e4f461 100644
@@ -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(&regs->ctrl);
 		v &= ~SUNXI_PWM_CTRL_CLK_GATE;
 		writel(v, &regs->ctrl);
 		v &= ~SUNXI_PWM_CTRL_PRESCALE0_MASK;
-		v |= (prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK);
+		v |= (best_prescaler & SUNXI_PWM_CTRL_PRESCALE0_MASK);
 		writel(v, &regs->ctrl);
 		v |= SUNXI_PWM_CTRL_CLK_GATE;
 		writel(v, &regs->ctrl);
-		priv->prescaler = prescaler;
+		priv->prescaler = best_prescaler;
 	}
 
-	writel(SUNXI_PWM_CH0_PERIOD_PRD(period) |

drivers/pwm/sunxi_pwm.c static int sunxi_pwm_set_config(struct udevice *dev, uint channel, · line 121

Quoted 10 lines
drivers/pwm/sunxi_pwm.c +2 -1
+	writel(SUNXI_PWM_CH0_PERIOD_PRD(best_period) |
 	       SUNXI_PWM_CH0_PERIOD_DUTY(duty), &regs->ch0_period);
 
 	debug("%s: prescaler: %d, period: %d, duty: %d\n",
 	      __func__, priv->prescaler,
-	      period, duty);
+	      best_period, duty);
 
 	return 0;
 }

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 227 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20181018/fac95c6f/attachment.sig>

#4 lore raw

PATCH 3/3 pwm: sunxi: choose best prescaler to improve PWM resolution

In reply to Vasily Khoruzhick
Quoted 4 lines · Vasily Khoruzhick

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.

#5 lore raw

PATCH 3/3 pwm: sunxi: choose best prescaler to improve PWM resolution

Quoted 9 lines · Jagan Teki
Quoted 4 lines · Vasily Khoruzhick

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.

#6 lore raw

PATCH 3/3 pwm: sunxi: choose best prescaler to improve PWM resolution

In reply to Vasily Khoruzhick
Quoted 7 lines · Vasily Khoruzhick

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.

---

Applied to all to u-boot-sunxi/master

#7 lore raw

PATCH 3/3 pwm: sunxi: choose best prescaler to improve PWM resolution

I think this series already went into Anatolij's u-boot-staging/agust at denx.de, please make sure that you don't introduce any conflicts.On Wed, Oct 24, 2018 at 9:28 AM Jagan Teki

Quoted 11 lines · <[email protected]> wrote:
Quoted 7 lines · Vasily Khoruzhick

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.

---

Applied to all to u-boot-sunxi/master

#8 lore raw

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

In reply to Vasily Khoruzhick
Quoted 4 lines · Vasily Khoruzhick

Fix off-by-one that prevented PWM driver to use prescaler bypass. Without this change prescaler is always enabled.

For the whole series,

Thanks!
Maxime

Signature · 3 lines
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
#9 lore raw

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

In reply to Vasily Khoruzhick
Quoted 7 lines · On Tue, 16 Oct 2018 21:56:33 -0700 Vasily Khoruzhick anarsoul at gmail.com…

Fix off-by-one that prevented PWM driver to use prescaler bypass. Without this change prescaler is always enabled.

---
 drivers/pwm/sunxi_pwm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Applied whole series to u-boot-staging/agust at denx.de, thanks!

--
Anatolij