Custom pinmux

Hello everyone,

I’m learning the device tree specifics and I’m only beginner in this. I’d like to create a custom device tree overlay for changing the pin mode at boot time.
I have a program for PRU which outputs something on PRU UART. I’ve tested that if I configure the pins using config-pin utility, I get the output.
Now I’m trying to achieve the same effect with device tree overlay. What I did:

  1. Cloned GitHub - mvduin/overlay-utils: Making BBB overlays easier
  2. Created pru-uart.dtsi file inside overlay-utils directory. Its contents:
#include "bone/black.h"

USES_PIN( P9_17 );  // pr1_uart0_txd
USES_PIN( P9_18 );  // pr1_uart0_rxd

/ {
	pr1_uart0 {
		compatible = "pr1-uart0";

		pinctrl-names = "default";
		pinctrl-0 = <&pr1_uart0_pins>;
	};
};

&am33xx_pinmux {
	pr1_uart0_pins: pr1_uart0 {
		pinctrl-single,pins = <
			PIN_PULLUP( P9_17, 4 )	// txd
			PIN_PULLUP( P9_18, 4 )	// rxd
		>;
	};
};
  1. Built it with make pru-uart.dtbo
  2. Copied the resulting file to /lib/firmware/
  3. Added it to /boot/uEnv.txt

But I’m getting no output when I run the PRU software.
Could you please help me troubleshoot this. What am I doing wrong?

PS I found that if I change the line to compatible = "gpio-of-helper"; or compatible = "bone-pinmux-helper";, it configures the pin modes as needed. But currently it looks like black magic to me. Could you please explain what’s going on here? Or point me in some direction to good read on device tree technology.

The problem is that the kernel isn’t going to do anything with a pinmux declaration unless it’s attached to a real device node, so you can’t just make up a non-existent node with a compatible-string that doesn’t match any driver.

Setting the compatible-string to gpio-of-helper works because this will create a virtual device normally used to configure and export gpios, though in your case you’d be using it to setup zero gpios but just use the side-effect of the default pinmux state getting selected, thus applying the pinmux in your &pr1_uart0_pins node.

Setting the compatible-string to bone-pinmux-helper works because this will create a virtual device used to allow userspace to switch between the pinmux states declared by the node (which is the mechanism used to allow config-pin to work). In your case it only has one pinmux state, "default", which as the name suggests is selected by default.

While both of these “solutions” work, neither of them is the correct way this is supposed to work. The appropriate solution is attaching your pinmux to the device for which the pinmux is intended. In this case the pru uart itself isn’t represented as a device since it is private to pru and not something the kernel interacts with or cares about, so the best thing to do is to attach the pinmux to the pruss node itself:

#include "bone/black.h"

USES_PIN( P9_17 );  // pruss uart txd
USES_PIN( P9_18 );  // pruss uart rxd

&pruss {
	pinctrl-names = "default";
	pinctrl-0 = <&pruss_pins>;
};

&am33xx_pinmux {
	pruss_pins: pruss {
		pinctrl-single,pins = <
			PIN_PULLUP( P9_17, 4 )	// pruss uart txd
			PIN_PULLUP( P9_18, 4 )	// pruss uart rxd
		>;
	};
};

Note that you’ll want to do all pinmux setup for pruss in one overlay. While it is possible to attach multiple pinmux nodes to a single state (pinctrl-0 = <&some_pins>, <&other_pins>;), you’d still need one particular overlay to set that property (since overlays sadly can’t append values to DT properties, they can only overwrite properties).