Issue enabling PWM1 or Backlight on IMX8MM

Good afternoon,

I have been developing a slightly customized build of Toradex Linux for the IMX8MM. This is used in a few variants of our in-house hardware. One variant uses GPIO5[5] as a GPIO for power supply control, and another variant is hoping to use that same pin as a PWM for fan control.

I am able to bring up that pin as a GPIO line and fully control it. However, all of my attemps to control it as a PWM have failed. We were able to find in one of the manuals that “pwm1 is dedicated to the backlight,” and were hoping to get more clarification on that.

Ultimately we do not need absolute control over this pin. The 16 statically defined “brightnesses” would be totally fine for our fan control if this pin cannot be separated from the backlight device. Bringing it up as either an available pwmchip or as backlight are both acceptable options.

Currently when I define all of the pwm# nodes in the device tree, I am able to set pwm2, pwm3, and pwm4 to any of their possible pins. pwm1 never appears in /sys/class/ (pwm2 becomes pwmchip0, pwm3 becomes pwmchip1, etc). Similarly, when I attempt to instantiate the backlight node, it does appear in /sys/class/, but is completely empty and seemingly cannot be controlled.

We are using kernel 5.4-2.1 in an offline build environment for this image. Updating the kernel would be a major headache, but I would be happy to apply patch files or make any updates to bitbake recipes or layers.

Thank you.

We have also attempted to read a number of registers related to this pin using devmem2. Reading most of the pinmux/pinctrl registers throws a Bus Error (perhaps because the 0x3xxxxxxx registers are not memory mapped?). We were able to find a separate set of registers which theoretically control the read/write-ability of other registers. All are set to “non-readable/non-writable” which fits the Bus Error issue, but Linux crashes when we attempt to modify those values. Any insight into how to check these registers would be appreciated as well.

Greetings @spencerarrasmith,

First of all what version of our software is your customized build based on? Also are you based on our BSP reference images or our TorizonCore images? It’s not completely clear which you are using.

As for your questions let me see if I can help clarify.

Currently when I define all of the pwm# nodes in the device tree, I am able to set pwm2, pwm3, and pwm4 to any of their possible pins.

By default our Verdin modules have 3 PWMs defined. Here in your post you mention 4 different PWMs, have you made modifications to alter/enable additional PWMs?

In any case I checked our 5.7.0 releases and by default 2 pwmchips can be used:

ls /sys/class/pwm/pwmchip
pwmchip0/ pwmchip1/

As you mentioned one PWM interface is used as a backlight. To have this other PWM available for general use you need to disable it’s use in the device tree as a backlight. Once you do that you should see then 3 pwmchips available:

ls /sys/class/pwm/pwmchip
pwmchip0/ pwmchip1/ pwmchip2/

As I said this is on our Version 5.7.0 OSes which uses the 5.4-2.3 kernel version. But the PWM pins and usage look to be the same as in the 5.4-2.1 kernel version.

I hope I was able to clear things up somewhat.

Best Regards,
Jeremias

Hey Jeremias, thanks for your reply. I am using an IMX8MM Verdin v1.1B, TorizonCore 5.4.0, Linux kernel 5.4-2.1, and building the custom image with Yocto Dunfell.

The four PWMs I am referring to are listed here: imx8mm.dtsi « freescale « dts « boot « arm64 « arch - linux-toradex.git. I have only made changes to pwm1 (PWM_3_DSI) and then pwm2 once I ran into these problems. pwm3 and pwm4 are not needed, so that is not a concern.

The main problem here is that the GPIO5[5] (SODIMM 208) pin is already routed to an external header on a physical board. It was chosen by the board designers because it was described in the manual/datasheet that it could be controlled as either a GPIO or a PWM (i.e. future-proofing that header by making it a bit more flexible). So far I have been unable to control specifically that pin as a PWM.

I will need to run a few more image builds to show the /sys/class issues that I described, but I will return with more information soon. Thank you.

The four PWMs I am referring to are listed here:

What you linked shows that the i.MX8M Mini SoC is capable of 4 PWM interfaces simultaneously. However, As seen in our higher level device tree: imx8mm-verdin.dtsi « freescale « dts « boot « arm64 « arch - linux-toradex.git - Linux kernel for Apalis, Colibri and Verdin modules

We only define and enable 3 of these interfaces. The 4th one isn’t fully configured in our software by default.

The main problem here is that the GPIO5[5] (SODIMM 208) pin is already routed to an external header on a physical board. It was chosen by the board designers because it was described in the manual/datasheet that it could be controlled as either a GPIO or a PWM (i.e. future-proofing that header by making it a bit more flexible). So far I have been unable to control specifically that pin as a PWM.

I checked and SODIMM 208 can be configured as a PWM for interface pwm1 (going off device tree numbering). But by default this pin is a GPIO not a PWM. You need to modify the device tree to have pwm1 use this pin instead of the default SODIMM 19.

Did you do such a change in the modifications you mentioned?

Best Regards,
Jeremias

Hi Jeremias,

Thank you for clarifying, but please forget the 3 PWMs versus 4 PWMs topic. I really only need PWM1 to function and mentioned that as an example that, generally speaking, I am able to get any and all PWMs to work except for PWM1 on SODIMM 208.

I have modified pinctrl_pwm1 inside imx8mm-verdin.dtsi:

        pinctrl_pwm_1: pwm1grp {
                fsl,pins = <
                        MX8MM_IOMUXC_SPDIF_EXT_CLK_PWM1_OUT              0x116   /* SODIMM 208 */
                >;
        };

The &pwm1 node definition which uses this pinctrl inside imx8mm-verdin.dtsi is unchanged. imx8mm-verdin-dahlia.dtsi sets this pwm to “okay.”

We have tried two builds this afternoon, and both seem to give the same result. We confirmed within the temp folders of Yocto that the correct .dtsi files are being applied to the device tree. I’ll summarize the changes and what we see in the image:

  1. backlight status = “disabled”
    &pwm1 using MX8MM_IOMUXC_SPDIF_EXT_CLK_PWM1_OUT (SODIMM 208), status = “okay”
    &pwm2 using MX8MM_IOMUXC_SPDIF_RX_PWM2_OUT (SODIMM 15), status = “okay”
    &pwm3 using MX8MM_IOMUXC_SPDIF_TX_PWM3_OUT (SODIMM 16), status = “okay”

  2. /delete-node/backlight; in .dtsi file included after the node is defined
    &pwm1 on SODIMM 208, status = “okay”
    &pwm2 on SODIMM 15, status = “okay”
    &pwm3 on SODIMM 16, status = “okay”

No other devices or pinctrl groups in any of the included .dtsi files are trying to use the SPDIF_EXT_CLK line, and backlight is the only device which is trying to use pwm1.

In both images, I see backlight inside /sys/class/, but the directory is completely empty. /sys/class/pwm/ contains pwmchip0 and pwmchip1. I have full control over pwmchip0 and pwmchip1 (SODIMM 15 and SODIMM 16 respectively) using echo 0 > export, etc. “&pwm1” is missing completely from /sys/class/ as far as I can tell.

This is the simplest explanation of my issue:

backlight: status = “disabled”
&pwm1: MX8MM_IOMUXC_SPDIF_EXT_CLK_PWM1_OUT (SODIMM 208), status = “okay”
&pwm2: MX8MM_IOMUXC_SPDIF_RX_PWM2_OUT (SODIMM 15), status = “okay”
&pwm3: MX8MM_IOMUXC_SPDIF_TX_PWM3_OUT (SODIMM 16), status = “okay”

becomes

/sys
  /class
    /backlight
      [nothing]
    /pwm
      /pwmchip0 on SODIMM 15
      /pwmchip1 on SODIMM 16

I just tried myself and it seems to work fine, I get 3 entries in /sys/class/pwm/pwmchip*. You said you set SODIMM 208 under pwm1 in the device tree, but as I said previously SODIMM 208 is a GPIO by default. Did you also remember to remove SODIMM 208 from it’s use as a GPIO?

Otherwise, you’d be trying to assign this pin to 2 different functions at once. This can result in either one or both functions not working due to the conflict.

Best Regards,
Jeremias

Yes, the first change I made was to remove the GPIO pin definition:

No other devices or pinctrl groups in any of the included .dtsi files are trying to use the SPDIF_EXT_CLK line, and backlight is the only device which is trying to use pwm1.

Can you please describe what you changed in the device tree? What version of TorizonCore are you building? What board are you using?

These are the only changes I made:

 &iomuxc {
        pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_gpio1>, <&pinctrl_gpio2>,
+       pinctrl-0 = <&pinctrl_gpio1>,
                    <&pinctrl_gpio3>, <&pinctrl_gpio4>,
                    <&pinctrl_gpio7>, <&pinctrl_gpio8>,
                    <&pinctrl_gpio_hog1>, <&pinctrl_gpio_hog2>, <&pinctrl_gpio_hog3>,
@@ -1107,7 +1107,7 @@
        /* Verdin PWM_3_DSI shared with GPIO1_IO1 */
        pinctrl_pwm_1: pwm1grp {
                fsl,pins = <
-                       MX8MM_IOMUXC_GPIO1_IO01_PWM1_OUT                0x6     /* SODIMM 19 */
+                       MX8MM_IOMUXC_SPDIF_EXT_CLK_PWM1_OUT             0x6     /* SODIMM 19 */
                >;
        };

These were made to the imx8mm-verdin.dtsi file. I tested this on TorizonCore 5.7.0 which uses the kernel source branch toradex_5.4-2.3.x-imx. The carrier board I was using was the Dahlia board.

As for the changes themselves they were pretty straightforward, just change the pin being used for pwm1 then remove SODIMM 208 from it’s default usage as a GPIO pin.

I didn’t physically test the PWM pin with hardware, but it enumerates in /sys/class/pwm/pwmchip* which should be enough.

Best Regards,
Jeremias

We were able to find the issue today.

Torizon is set up to load a specific .dtb file based on a value called TORADEX_PRODUCT_IDS which lives inside meta-toradex-nxp/conf/machine/verdin-imx8mm.conf. Also inside this file is the variable TEZI_EXTERNAL_KERNEL_DEVICETREE_BOOT = "verdin-imx8mm_lt8912_overlay.dtbo"

We are using the dunfell-5.x.y version of the layer: verdin-imx8mm.conf « machine « conf - meta-toradex-nxp.git and building a slightly modified tdx-reference-minimal-image.

The LT8912 device tree overlay is meant to control the HDMI bridge, which encompasses the backlight control and thereby PWM1. No matter what we did to remove backlight and take control of PWM1 inside our own device tree files, this overlay was creating the backlight device and taking control of PWM1 for the HDMI bridge. We were able to remove it from /boot/overlays.txt which restored PWM1.

The final fix will be setting TEZI_EXTERNAL_KERNEL_DEVICETREE_BOOT = "" to eliminate the overlay and have full control over PWM1 as /sys/class/pwm/pwmchip0

Glad you were able to resolve the issue.