why is pinmux-helper needed?

If there is a better place for this post please move - after all, pinmux is for more than GPIO, right?

I’ve been trying to figure out why pinmux-helper is needed. I’ve searched and found initial RFC and followup in the early years (by Charles Steinkuehler) and I understand the motivation (I think) as stated, but I don’t understand the basics behind the why.

Before pinmux-helper was provided, wasn’t it possible to use sysfs to change pinmux and gpio settings for all exported pins? Weren’t all pins exported? (If not, couldn’t exporting them all have been an alternate solution?) And couldn’t loading a device tree fragment be used to change the current state? If changes to pin state were to be made frequently, I can see how those methods would be cumbersome; however, isn’t pin state configuration something that is done rather infrequently, as it implies that the BBB is being repurposed and connected to different hardware (physically)?

This question extends to config-pin utility, as well as the cape-universal (and associated) dtb files. Wasn’t all this possible already?

Let me be clear that I’m not criticizing the work that has been done - rather I’m trying to use the evolution of capes, cape manager, dtb, drivers etc as a way of better understanding how the underlying drivers, device trees, and sysfs controls work.

You need to understand how the pins are configured when defined in the devicetree. It is the driver that does the pin configuration as defined in the devicetree. Without an associated driver, the pins defined in the devicetree won’t do anything. When using PRU, there is no driver, so the pins don’t get configured and hence that is why pinmux-helper is necessary.

Regards,
John

This may be a rudimentary linux/dt question, but doesn’t the pinctrl-single driver already support this? Couldn’t one change the pin configuration by loading a dtc overlay?

pinctrl-single provides a way to set pinmux values, but not a way to
switch between various sets of values.

And yes, you can change the pinmux values by loading a device tree
overlay, but you cannot do this repeatedly (ie: load several device
tree overlays in sequence that modify the same pin) and there is no
way to control individual pins without having individual device tree
overlays for each pin and separating the hardware drivers (ie: timer,
uart, etc) from the pinmux overlays. If you do this, you have
basically recreated the cape-universal overlays as a series of many
small files instead of a single overlay (except you have to
load/unload overlays to change the pin muxing rather than just write
to a file in sysfs).

Thank you for the reply. I am beginning to see how this could make things easier. If you will bear with me, I’d like to poke a little deeper, to further my understanding of exactly how this all works. I’ll be referring specifically to the BBB, but if there are general embedded Linux implications feel free to expand.

TLDR; This got really long. The executive summary might be "can you point me towards resources that will help me further understand the new approach used by the universal cape and pinmux-helper/gpio-of-helper? (I’ve left the more detailed questions below if you have the patience & generosity to review and reply)

Is any of this incorrect/incomplete? -

  1. pin configuration ultimately boils down to two steps, for every pin (ball on the SoC): what is it internally connected to (and operationally configured), and separately, controlling that function once connected.

  2. specifying the function/connection and operation is what the “traditional” pinmux (“pinctrl-single”) entries do. It is accomplished by setting values in GPIO control registers, which is just writing values to locations in the SoC memory mapped space (with pinmux child nodes using “pinctrl-single,pins” driver to specify offset from pinmux base address and mode selection, in 2-tuples for each pin being configured). It is a bit tricky because this requires privilege and thus a kernel driver (in kernel space/ring 0). The selection of function/connection is done by the “mode” bits (2:0) in the control register, and the operation by other bits (pullup/down, pull-enable, receiver enable, slew rate).

*I haven’t tried it (don’t want to damage hardware) but does this mean that directly poking at the GPIO registers from userspace with /dev/mem & mmap() won’t work?
*if this is correct so far, what prevents loading a series of cape overlays that change the configuration of a pin with this “old” style of pinmux control?

  1. this is where things start being less clear to me: I think I was just understanding pinmuxing; now I see devices with properties “pinctrl-0;” with no value. Is that because the devices no longer “own” their pins, but the config-pin driver does?
  2. the cape-universal node uses the “gpio-of-helper” driver, and apparently has a node for each header pin, with a 3-tuple. It looks like {mode,?,0} but that’s a guess. I’ve searched, and found some examples from Pantelis Antoniou, but no explanation.

Ultimately, I’d like to understand this so that I can create mappings/dts on my own, rather than just relying on finding something that works offered by someone else.

1) pin configuration ultimately boils down to two steps, for every pin (ball on
the SoC): what is it internally connected to (and operationally configured), and
separately, controlling that function once connected.

Yes. The physical pin is connected to a pin multiplexer, which is
generally completely separate from any logical device (gpio, uart,
timer, etc) that might use the pin.

2) specifying the function/connection and operation is what the "traditional"
pinmux ("pinctrl-single") entries do. It is accomplished by setting values in
GPIO control registers, which is just writing values to locations in the SoC
memory mapped space (with pinmux child nodes using "pinctrl-single,pins" driver
to specify offset from pinmux base address and mode selection, in 2-tuples for
each pin being configured). It is a bit tricky because this requires privilege
and thus a kernel driver (in kernel space/ring 0). The selection of
function/connection is done by the "mode" bits (2:0) in the control register,
and the operation by other bits (pullup/down, pull-enable, receiver enable, slew
rate).

Yes, with the caveat that different systems may have different ways of
specifying the pinmux control. The BBB uses two values, but there are
many different flavors of pinmux control across the various SoC's
available.

*I haven't tried it (don't want to damage hardware) but does this mean that
directly poking at the GPIO registers from userspace with /dev/mem & mmap()
won't work?
*if this is correct so far, what prevents loading a series of cape overlays that
change the configuration of a pin with this "old" style of pinmux control?

In the "old days", you could do this if you were root. Now I believe
the hardware configuration register space is setup with memory
protections so you have to access it from kernel space or you get an
exception. You can still work around this if you're root by playing
"tricks" (you can use something like the DMA engine or PRU to write
values to the pinmux registers, bypassing the MMU).

3) this is where things start being less clear to me: I think I was just
understanding pinmuxing; now I see devices with properties "pinctrl-0;" with no
value. Is that because the devices no longer "own" their pins, but the
config-pin driver does?

Not every device need to manage pins. Some devices don't have any
pins (a DMA controller, cryptographic acceleartor, etc) and sometime
the pins are already setup or are controlled by a different driver
(like the pinmux-helper driver).

4) the cape-universal node uses the "gpio-of-helper" driver, and apparently has
a node for each header pin, with a 3-tuple. It looks like {mode,?,0} but that's
a guess. I've searched, and found some examples from Pantelis Antoniou, but no
explanation.

The gpio-of-helper exports the GPIO pins so this doesn't have to be
done by the user. The three values you are referring to describe a
particular GPIO pin. The number of values needed, and their meaning
is device specific:

https://www.kernel.org/doc/Documentation/devicetree/bindings/gpio/gpio.txt

Ultimately, I'd like to understand this so that I can create mappings/dts on my
own, rather than just relying on finding something that works offered by someone
else.

Read through the device tree binding documentation in the kernel
source. It is also helpful to view the full working device tree from
your system. You can take the binary device tree from /boot and
convert it into source with dtc. Then instead of a bunch of dangling
references like &gpio3, you can go to gpio3 and see what it is, which
will help you find it's documentation in the kernel's Documentation
directory.

*I haven’t tried it (don’t want to damage hardware) but does this mean that
directly poking at the GPIO registers from userspace with /dev/mem & mmap()
won’t work?
*if this is correct so far, what prevents loading a series of cape overlays that
change the configuration of a pin with this “old” style of pinmux control?

Using the “old” method, why can’t cape overlays be repeatedly used to reconfigure pins? (Not that it is a better
method than the universal cape and config-pin utility - just that I must be missing something
important in understanding how this works).

In the “old days”, you could do this if you were root. Now I believe
the hardware configuration register space is setup with memory
protections so you have to access it from kernel space or you get an
exception. You can still work around this if you’re root by playing
“tricks” (you can use something like the DMA engine or PRU to write
values to the pinmux registers, bypassing the MMU).

If I map these IO configuration registers using /dev/mem and access, am I not enlisting the kernel (with it’s privileges)?
(If this opens up an entirely new topic on memory access and user space, let’d defer to avoid further scope creep)

  1. this is where things start being less clear to me: I think I was just
    understanding pinmuxing; now I see devices with properties “pinctrl-0;” with no
    value. Is that because the devices no longer “own” their pins, but the
    config-pin driver does?

Not every device need to manage pins. Some devices don’t have any
pins (a DMA controller, cryptographic acceleartor, etc) and sometime
the pins are already setup or are controlled by a different driver
(like the pinmux-helper driver).

OK, that makes sense. But then why is there a pinctrl-0 property at all (why not omit that property entirely)?
If the node is configuring a specific device, with it’s own driver, then the driver could not
even look for that property, as there are no pins associated with the device.
Is this a way of reusing existing drivers and avoiding bloat of one-driver-per-device?

  1. the cape-universal node uses the “gpio-of-helper” driver, and apparently has
    a node for each header pin, with a 3-tuple. It looks like {mode,?,0} but that’s
    a guess. I’ve searched, and found some examples from Pantelis Antoniou, but no
    explanation.

The gpio-of-helper exports the GPIO pins so this doesn’t have to be
done by the user. The three values you are referring to describe a
particular GPIO pin. The number of values needed, and their meaning
is device specific:

https://www.kernel.org/doc/Documentation/devicetree/bindings/gpio/gpio.txt

Thanks, this is a great source of information - though hard to find some things in the hierarchy
(as someone that doesn’t have enough experience to follow the structure without searching around.
ex: gpio-of-helper is not found under ./bindings/gpio. Where can I find that?).

If pins are exported using gpio-of-helper, are they then unavailable for direct use (“ownership”?)
by devices that are configured in the dt? For instance, if I want to enable a UART and configure (pinmux)
pins for it’s exclusive use, do I need to modify the dt to not export those pins using gpio-of-helper?
Or will they coexist - but then could a user use config-pin and 'steal" those pins from the UART?
Has the dt “exclusive-use = …” concept been deprecated as well?

Ultimately, I’d like to understand this so that I can create mappings/dts on my
own, rather than just relying on finding something that works offered by someone
else.

Read through the device tree binding documentation in the kernel
source. It is also helpful to view the full working device tree from
your system. You can take the binary device tree from /boot and
convert it into source with dtc. Then instead of a bunch of dangling
references like &gpio3, you can go to gpio3 and see what it is, which
will help you find it’s documentation in the kernel’s Documentation
directory.

I meant to include in the previous post that I am looking at a complete dt (I think) that
I extracted from the running system using the “dtc -I fs” option.