enable_uart=1 does not cause corresponding GPIOs to be busy
Describe the bug
I set enable_uart=1 in /boot/config.txt to enable access to a serial console on GPIO14+15. This works perfectly fine. However, the kernel sees those GPIOs still as "unused", even though they are actively used by the UART:
$ lsgpio -n gpiochip0
GPIO chip: gpiochip0, "pinctrl-bcm2711", 58 GPIO lines
[...]
line 14: "GPIO14" unused [input]
line 15: "GPIO15" unused [input]
This means that I can execute something like gpioset GPIO15=low and break UART functionality. I would rather expect gpioset to complain gpioset: unable to request lines on chip '/dev/gpiochip0': Device or resource busy as it does for other GPIOs when they are already in use (e.g. when using dtoverlay=gpio-shutdown,gpio_pin=26 and trying to execute gpioset GPIO26=low).
Steps to reproduce the behaviour
- Set
enable_uart=1in/boot/config.txtand reboot - Run
gpioset GPIO15=low - Observe that the command succeeds unexpectedly and UART functionality is now broken
Device (s)
Raspberry Pi 3 Mod. B+, Raspberry Pi 4 Mod. B
System
Arch Linux ARM
$ vcgencmd version
May 14 2025 12:23:36
Copyright (c) 2012 Broadcom
version 17084b403fb60475b8ee2641c26049a7d54bf153 (clean) (release) (start)
$ uname -a
Linux rpi 6.12.43-1-rpi #1 SMP PREEMPT Tue Aug 26 13:22:07 MDT 2025 aarch64 GNU/Linux
Logs
No response
Additional context
No response
The GPIO and pinctrl spaces are currently independent. It should be possible to enable "strict" mode, but numerous things would be likely to break and require attention - there might even be some use cases relying on the flexibility - so the motivation to fix this is very low.
Is there an easy way for me to mark those GPIOs as in use? Something like dtoverlay=gpio-shutdown,gpio_pin=26, but without activating any functionality on the pin?
I could write some application that just opens the GPIO without doing anything with it, but then I'd have to rely on that application always running, so I'd prefer something on the dtoverlay= level that is always active, so there can be no race conditions, application crashes, etc. that would allow some other application to use the GPIO and break UART functionality.
I could write some application that just opens the GPIO without doing anything with it
Or maybe I can't? As soon as I open one of the UART GPIOs from some application, the UART functionality is broken and can only be restored by rebooting (not by closing the GPIO or the application). I'd guess this is due to the GPIO hardware getting reconfigured (since when opening a GPIO, I have to specify whether to open it as input or output) and I don't know how to restore the original configuration used by the UART.
Any other idea how I can block all applications from opening specific GPIOs?
Any other idea how I can block all applications from opening specific GPIOs?
You should be able to use GPIO hogs:
$ dtoverlay -h gpio-hog
Name: gpio-hog
Info: Activate a "hog" for a GPIO - request that the kernel configures it as
an output, driven low or high as indicated by the presence or absence
of the active_low parameter. Note that a hogged GPIO is not available
to other drivers or for gpioset/gpioget.
Usage: dtoverlay=gpio-hog,<param>=<val>
Params: gpio GPIO pin to hog (default 26)
active_low If set, the hog drives the GPIO low (defaults
to off - the GPIO is driven high)
Try this:
dtoverlay=gpio-hog,gpio=14
dtoverlay=gpio-hog,gpio=15
The kernel will reserve them, driving them high by default (you can override that with the active_low parameter. This seems to happen before the pinctrl operations, which then change the function selector to whatever is required, TXD0 and RXD0 in the case of GPIOs 14 and 15, at which point the other function controls the drive.
Thanks, but this does not seem to work. It marks the GPIOs as used, but it also breaks the serial functionality, similar to my other experiments.