Overlay PWM-Backlight

Hello Toradex team,

I hope you are all doing great!

Hardware:

uname:

  • Linux verdin-imx8mp-14773423 5.15.77-6.2.0+git.aa0ff7e3554e #1-TorizonCore SMP PREEMPT Wed Mar 29 15:33:40 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux

Images tested:

  • torizon-core-docker-verdin-imx8mp-Tezi_6.2.0+build.2.tar (STABLE Release)

Guest OS:

  • macOS (M1 Pro ARM64)
  • Linux ubuntu (VM x86_64)

Issue:
The Goal is to create a new backlight control through sysfs. So I wrote a new pwm-backlight object on my custom carrier board as follow:

/ {
	backlight_fline: backlight-fline {
		compatible               = "pwm-backlight";
		brightness-levels        = <0 17 34 51 68 85 102 119 136 153 170 187 204 221 238 255>;
		default-brightness-level = <12>;

		enable-gpios             = <&gpio4 25 GPIO_ACTIVE_HIGH>; /* SODIMM 17 */

		power-supply             = <&reg_3p3v>;

		pwms                     = <&pwm4 0 6666667 PWM_POLARITY_NORMAL>;
		status                   = "okay";
	};
};

I have followed the instruction from this: link to write the overlay.

I can build it with torizoncore-builder, the overlay is properly applied but there is nothing on the sysfs folder related to backlight:

$ ls -l /sys/class/backlight/
total 0

The PWM is properly set, but not bind to a kernel module:

$ sudo cat /sys/kernel/debug/pwm
Password:
platform/30690000.pwm, 1 PWM device
 pwm-0   ((null)              ): period: 0 ns duty: 0 ns polarity: normal

platform/30680000.pwm, 1 PWM device
 pwm-0   ((null)              ): period: 0 ns duty: 0 ns polarity: normal

platform/30670000.pwm, 1 PWM device
 pwm-0   ((null)              ): period: 0 ns duty: 0 ns polarity: normal

platform/30660000.pwm, 1 PWM device
 pwm-0   ((null)              ): period: 0 ns duty: 0 ns polarity: normal

When I link this backlight_fline to the LVDS display and enable it, it works, but I don’t want to use this LVDS display for now (the carrier board as the wrong pin mapping).

I hope you will be able to help me in my request.

Kind regards,

M

Greetings @unablesalt,

First of all just to be clear the code-snippet you provided, is that a snippet of your device tree or is that your overlay in it’s entirety?

Secondly, I did a quick test where I applied the following overlay:

/dts-v1/;
/plugin/;

/ {
	compatible = "toradex,verdin-imx8mp";
};

&backlight {
	status = "okay";
};

This references the already existing backlight node in our default device tree. With this I was able to get a backlight listing in sysfs:

torizon@verdin-imx8mp-06849059:~$ ls -l /sys/class/backlight/backlight/
total 0
-r--r--r-- 1 root root  4096 Jun 20 19:54 actual_brightness
-rw-rw-r-- 1 root video 4096 Jun 20 19:53 bl_power
-rw-rw-r-- 1 root video 4096 Jun 20 19:53 brightness
lrwxrwxrwx 1 root root     0 Jun 20 19:54 device -> ../../../backlight
-r--r--r-- 1 root root  4096 Jun 20 19:53 max_brightness
drwxr-xr-x 2 root root     0 Jun 20 19:54 power
-r--r--r-- 1 root root  4096 Jun 20 19:54 scale
lrwxrwxrwx 1 root root     0 Jun 20 19:53 subsystem -> ../../../../../class/backlight
-r--r--r-- 1 root root  4096 Jun 20 19:53 type
-rw-r--r-- 1 root root  4096 Jun 20 19:53 uevent

That is to say this should work in theory.

Best Regards,
Jeremias

Hello @jeremias.tx,

Thank you for your reply!

The code provided is an overlay added on top of the imx8mp-verdin-wifi-dahlia.dts device tree.

I checked what you said, and backlight is a bit different from my declaration:

backlight: backlight {
		compatible = "pwm-backlight";
		brightness-levels = <0 45 63 88 119 158 203 255>;
		default-brightness-level = <4>;
		/* Verdin I2S_2_D_OUT (DSI_1_BKL_EN/DSI_1_BKL_EN_LVDS, SODIMM 46) */
		enable-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_i2s_2_d_out_dsi_1_bkl_en>;
		power-supply = <&reg_3p3v>;
		/* Verdin PWM_3_DSI/PWM_3_DSI_LVDS (SODIMM 19) */
		pwms = <&pwm3 0 6666667 PWM_POLARITY_INVERTED>;
		status = "disabled";
	};

As we can see we have pinctrl-names and pinctrl-0, what does that means ? I’m not 100% familiar with this code and device tree in general.

Unfortunately, I can’t test to enable backlight as you suggest since the pin are different from mine on my custom carrier board.

I agree with you that it should be logic, but for some reason, it’s not working…

Best regards,

M

As we can see we have pinctrl-names and pinctrl-0, what does that means ? I’m not 100% familiar with this code and device tree in general.

This refers to the pins that are assigned to this node. For example if you look for pinctrl_i2s_2_d_out_dsi_1_bkl_en in the device tree you’ll find this: imx8mp-verdin.dtsi « freescale « dts « boot « arm64 « arch - linux-toradex.git - Linux kernel for Apalis, Colibri and Verdin modules

Which is the pin configuration and assignment for the pin that is referenced in enable-gpios.

Another thing I noticed is that you’re referencing: pwms = <&pwm4 0 6666667 PWM_POLARITY_NORMAL>;

However, the node pwm4 is not configured in our device-tree. We only have pwm1, 2, and 3 configured by default. That could be another possible issue.

Best Regards,
Jeremias

Hello @jeremias.tx,

Here is the overlay that works only when I enable:

&panel_lvds_mez {
	status       = "okay";
...
};

Overlay:

&wm8904_1a {
	status        = "disabled";
};

//!# https://git.toradex.com/cgit/linux-toradex.git/tree/Documentation/devicetree/bindings/pwm/imx-pwm.yaml?h=toradex_5.15-2.1.x-imx
&pwm4 {
	pinctrl-names = "default";
	pinctrl-0     = <&pinctrl_pwm_4>;
	#pwm-cells    = <3>;

	status        = "okay";
};

&iomuxc {
	pinctrl_pwm_4: pwm4grp {
		fsl,pins =
			<MX8MP_IOMUXC_SAI5_RXFS__PWM4_OUT 0x6>; /* SODIMM 34 */
	};
};

//!# Disable
//!# Used: pinctrl_gpio_9_dsi -> SAI2_TXC (SODIMM 17)
&atmel_mxt_ts {
	status                   = "disabled";
};

//!# PWM is inverted in Toradex device tree
//!# https://git.toradex.com/cgit/linux-toradex.git/tree/Documentation/devicetree/bindings/pwm/pwm.txt?h=toradex_5.15-2.1.x-imx
&backlight_mezzanine {
	default-brightness-level = <12>;
	brightness-levels        = <0 17 34 51 68 85 102 119 136 153 170 187 204 221 238 255>;
	pwms                     = <&pwm4 0 6666667 PWM_POLARITY_NORMAL>;

	enable-gpios             = <&gpio4 25 GPIO_ACTIVE_HIGH>; /* SODIMM 17 */

	status                   = "okay";
};

And as you can see:

sudo cat /sys/kernel/debug/pwm
platform/30690000.pwm, 1 PWM device
 pwm-0   (backlight-mezzanine ): requested enabled period: 6666667 ns duty: 5333333 ns polarity: normal
platform/30680000.pwm, 1 PWM device
 pwm-0   ((null)               ): requested period: 40000 ns duty: 20000 ns polarity: normal

platform/30670000.pwm, 1 PWM device
 pwm-0   ((null)               ): requested period: 40000 ns duty: 20000 ns polarity: normal

platform/30660000.pwm, 1 PWM device
 pwm-0   ((null)               ): requested period: 40000 ns duty: 20000 ns polarity: normal

So I can use the backlight-mezzanine and play around with it in the:

$ ls -l /sys/class/backlight/backlight-mezzanine/
total 0
-r--r--r-- 1 root root  4096 Apr 28  2022 actual_brightness
-rw-rw-r-- 1 root video 4096 Apr 28  2022 bl_power
-rw-rw-r-- 1 root video 4096 Apr 28  2022 brightness
lrwxrwxrwx 1 root root     0 Jun 20 21:33 device -> ../../../backlight-mezzanine
-r--r--r-- 1 root root  4096 Apr 28  2022 max_brightness
drwxr-xr-x 2 root root     0 Jun 20 21:33 power
-r--r--r-- 1 root root  4096 Jun 20 21:33 scale
lrwxrwxrwx 1 root root     0 Apr 28  2022 subsystem -> ../../../../../class/backlight
-r--r--r-- 1 root root  4096 Apr 28  2022 type
-rw-r--r-- 1 root root  4096 Apr 28  2022 uevent

=========================

Now when I do this:

&panel_lvds_mez {
	status       = "disabled";
};

It’s not working anymore… I don’t have the backlight-mezzanine available nor loaded.

I suspect that I can’t use the backlight without a LVDS display, I couldn’t find any information related to this on internet…

Best regards,

M

I suspect that I can’t use the backlight without a LVDS display, I couldn’t find any information related to this on internet…

But in my post I just showed you that it works without a display. In my test I don’t have any display interfaces enabled:

torizon@verdin-imx8mp-06849059:~$ ls /sys/class/drm/
version

All my overlay did was enable backlight. That said I’m not sure why you’re trying to use the backlight with no display.

Now as for your overlay I took it did some slight but not major alterations and it works fine for me:

Test overlay
/dts-v1/;
/plugin/;

#include "dt-bindings/pwm/pwm.h"
#include "dt-bindings/gpio/gpio.h"
#include "imx8mp-pinfunc.h"

/ {
	compatible = "toradex,verdin-imx8mp";
};

&backlight_mezzanine {
	status = "okay";
        pwms = <&pwm4 0 6666667 PWM_POLARITY_INVERTED>;
        enable-gpios = <&gpio4 25 GPIO_ACTIVE_HIGH>;
};

&wm8904_1a {
	status = "disabled";
};

//!# https://git.toradex.com/cgit/linux-toradex.git/tree/Documentation/devicetree/bindings/pwm/imx-pwm.yaml?h=toradex_5.15-2.1.x-imx
&pwm4 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_pwm_4>;
	#pwm-cells = <3>;
	status = "okay";
};

&iomuxc {
	pinctrl_pwm_4: pwm4grp {
		fsl,pins =
			<MX8MP_IOMUXC_SAI5_RXFS__PWM4_OUT 0x6>; /* SODIMM 34 */
	};
};

No LVDS enabled and backlight can be seen in sysfs:

torizon@verdin-imx8mp-06849059:~$ sudo cat /sys/kernel/debug/pwm
Password:
platform/30690000.pwm, 1 PWM device
 pwm-0   (backlight-mezzanine ): requested period: 6666667 ns duty: 0 ns polarity: inverse

platform/30680000.pwm, 1 PWM device
 pwm-0   ((null)              ): period: 0 ns duty: 0 ns polarity: normal

platform/30670000.pwm, 1 PWM device
 pwm-0   ((null)              ): period: 0 ns duty: 0 ns polarity: normal

platform/30660000.pwm, 1 PWM device
 pwm-0   ((null)              ): period: 0 ns duty: 0 ns polarity: normal
torizon@verdin-imx8mp-06849059:~$ ls /sys/class/backlight/backlight-mezzanine/
actual_brightness  bl_power  brightness  device  max_brightness  power  scale  subsystem  type  uevent

By the way are you sure your overlay even compiled successfully? Because PWM_POLARITY_NORMAL is not a defined macro in the pwm device tree header: pwm.h « pwm « dt-bindings « include - linux-toradex.git - Linux kernel for Apalis, Colibri and Verdin modules

Which is why I replaced it with PWM_POLARITY_INVERTED in my test.

Best Regards,
Jeremias

Hello @jeremias.tx,

There was indeed an small mistake in my overlay, after fixing it, the device is registered.

&{/} {                                                               //!# <-- HERE
	backlight_fline: backlight-fline {
		compatible               = "pwm-backlight";
		brightness-levels        = <0 17 34 51 68 85 102 119 136 153 170 187 204 221 238 255>;
		default-brightness-level = <12>;

		enable-gpios             = <&gpio4 25 GPIO_ACTIVE_HIGH>; /* SODIMM 17 */

		power-supply             = <&reg_3p3v>;

		pwms                     = <&pwm4 0 6666667 0>;
		status                   = "okay";
	};
};

But, it’s not working… The PWM duty remains at 0, despite that I setup the brightness to the maximum:

/sys/class/backlight/backlight-fline$ ls -l
total 0
-r--r--r-- 1 root root  4096 Jun 21 09:47 actual_brightness
-rw-rw-r-- 1 root video 4096 Jun 21 09:47 bl_power
-rw-rw-r-- 1 root video 4096 Jun 21 09:48 brightness
lrwxrwxrwx 1 root root     0 Jun 21 09:48 device -> ../../../backlight-fline
-r--r--r-- 1 root root  4096 Jun 21 09:47 max_brightness
drwxr-xr-x 2 root root     0 Jun 21 09:48 power
-r--r--r-- 1 root root  4096 Jun 21 09:48 scale
lrwxrwxrwx 1 root root     0 Jun 21 09:47 subsystem -> ../../../../../class/backlight
-r--r--r-- 1 root root  4096 Jun 21 09:47 type
-rw-r--r-- 1 root root  4096 Jun 21 09:47 uevent
torizon@verdin-imx8mp-14773420:/sys/class/backlight/backlight-fline$ sudo cat /sys/kernel/debug/pwm
platform/30690000.pwm, 1 PWM device
 pwm-0   (backlight-fline     ): requested period: 6666667 ns duty: 0 ns polarity: normal

platform/30680000.pwm, 1 PWM device
 pwm-0   ((null)              ): period: 0 ns duty: 0 ns polarity: normal

platform/30670000.pwm, 1 PWM device
 pwm-0   ((null)              ): period: 0 ns duty: 0 ns polarity: normal

platform/30660000.pwm, 1 PWM device
 pwm-0   ((null)              ): period: 0 ns duty: 0 ns polarity: normal
torizon@verdin-imx8mp-14773420:/sys/class/backlight/backlight-fline$ cat actual_brightness
15
torizon@verdin-imx8mp-14773420:/sys/class/backlight/backlight-fline$ cat max_brightness
15

Can you check on your side that the PWM signal can be changed and output anything ?

The PWM 4 works when I use sysfs, can I can enable the backlight so it’s not an hardware problem. It’s most probably a software problem.

Best regards,

M

Hi @unablesalt !

I hope you are doing well :slight_smile:

I have two small comments (hopefully one of them are helpful):

  1. According to the documentation of pwm-backlight (pwm-backlight.yaml « backlight « leds « bindings « devicetree « Documentation - kernel/git/stable/linux.git - Linux kernel stable tree) the pwms property examples are using only 3 elements in the cell (pwm controller, pwm “line” and duty cycle). Have you tried removing the 3rd element (polarity configuration)?
    1.1. I know that it is indeed set in some PWM usages (pwm.txt « pwm « bindings « devicetree « Documentation - kernel/git/stable/linux.git - Linux kernel stable tree) but maybe it is worth the shot.
  2. Have you tried to use other brightness levels? None of them work?

Best regards,

Hello @henrique.tx,

I hope you are doing great ! Thank you for your message.

I tried what you asked, removing the last parameter of pwms:

pwms = <&pwm4 0 6666667>;

And it’s still not working. I can see that the backlight-fline takes the PWM spot, but I don’t see the backlight working…

For the second, I just tested and it doesn’t change. The PWM duty remains at 0 and of course, no signal when I try to probe it.

I did some research last night and I found this: Backlight pwm is not working - #21 by WayneWWW - Jetson AGX Xavier - NVIDIA Developer Forums I think, I really need to link a display to my backlight to actually be able to change it, or rewrite a module :disappointed:.

Best regards,

M

I think, I really need to link a display to my backlight to actually be able to change it, or rewrite a module

Just so we understand, why are you trying to use the backlight interface without a display in the first place? The backlight interface is kind of useless without an accompanying display interface.

Best Regards,
Jeremias

Hello @jeremias.tx,

Thank you for taking the time to help me, much appreciate!

Long story, short: the first 20 prototypes of our board have the wrong pin mapping for LVDS so it’s unusable at the moment. We are falling back on the HDMI->LVDS converter we have found online. And we have to use the build in backlight from our board to power the display.

The problem of setting LVDS and HDMI, we have 2 displays and I’m having a hard time to set the HDMI-A-1 as the primary.

Basically, it’s a walk around until we receive the correct carrier board.

For the moment, I created a service as explained in here and it’s working. Not the proper solution I would have expected.

[Unit]
Description=Backlight brightness service, set and store display brightness setting
After=multi-user.target

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/bin/sh -c 'echo 0 > /sys/class/pwm/pwmchip3/export && echo 6666667 > /sys/class/pwm/pwmchip3/pwm0/period && echo 5333333 > /sys/class/pwm/pwmchip3/pwm0/duty_cycle && echo 1 > /sys/class/pwm/pwmchip3/pwm0/enable'
ExecStop=/bin/sh -c 'echo 0 > /sys/class/pwm/pwmchip3/pwm0/enable && echo 0 > /sys/class/pwm/pwmchip3/unexport'

[Install]
WantedBy=multi-user.target

I’ll keep dig in the kernel’s code to understand why it’s blocking.

Best regards,
M

Hi @unablesalt,

we’re talking about your issue internally.

As soon as I have some news about this one, I’ll post it here.

Thanks for you patience.

Have a great week.

Best Regards
Kevin

1 Like