| GPIO(7) | Standards, Environments, and Macros | GPIO(7) |
gpio, dpio
— General and Dedicated Purpose I/O
General Purpose I/Os (gpio) are a common type of interface found in various microprocessors, ASICs, and other types of devices. A GPIO is functionality that hardware exposes that allows software to observe and control the state of a particular pin (or set of pins) on the device. These hardware pins may be connected to any number of different things ranging from enable and control lines, sensors, LEDs, or even a more complex hardware peripheral.
Software control of a GPIO generally gives you the ability to do things like:
The OS provides a dedicated subsystem for manipulating and interfacing with GPIOs in hardware. The rest of this manual goes into details about that subsystem, ways to constrain GPIOs for safety, and what tooling is available.
Device drivers register with the kernel GPIO subsystem which the OS organizes as a series of named GPIO Controllers. Each controller itself then enumerates a series of GPIOs that have a name and controller-specific ID which is used to manipulate the GPIO. In general, while tooling requires IDs, names are what GPIO controllers guarantee the stability of.
Each GPIO has a series of attributes that describe the different properties of the GPIO. The attributes of a GPIO are specific to the device driver that provides it. While most GPIO controllers provide similar features, the specifics often vary quite particularly. Let's take the example of control over integrated pull-up and pull-down resistors. Some hardware offers a very simple option of indicating whether there is a pull-up, pull-down, or none while others require you to specify the strength of the resistor, which of course varies from part to part (and some devices only let you control the strength in one direction), and then some hardware actually lets you enable both the pull-up and pull-down.
For concepts which are trickier to deal with, such as the drive strength or rise and fall times of signals, this turns into a larger mess. And of course, the last thing that is important to keep in mind is that not all GPIOs on a given controller are necessarily the same. As such, the OS does not try to commonize the different attributes. Instead, for each attribute, the following information is provided:
To make this concrete, here is an example of a GPIO's attributes as provided by the gpioadm(8) utility:
ATTR PERM VALUE POSSIBLE
name r- EGPIO9_3 --
zen:pad_name r- BP_AGPIO9_3 --
zen:pin r- CY41 --
zen:pad_type r- gpio --
zen:caps r- -- --
zen:output_driver r- push-pull push-pull
zen:voltage r- 3.3V 3.3V
zen:drive_strength rw 40R 40R,80R
zen:output rw disabled disabled,low,high
zen:input r- low low,high
zen:debounce_mode rw none none,keep-low-glitch,
keep-high-glitch,
remove-glitch
zen:debounce_unit rw 61us 61us,244us,15.6ms,62.5ms
zen:debounce_count rw 0x0 --
zen:trigger_mode rw edge/high edge/high,edge/low,
edge/both,level/high,
level/low
zen:status r- -- --
zen:pull rw disabled disabled,down,4k-up,
8k-up
zen:raw_reg r- 0x440000 --
Multiple attributes of a GPIO may be set at once.
Incorrect usage of GPIOs will damage your system. The way that GPIOs are used will vary from product to product and just because a GPIO is used in some way on one system has no bearing on another. The GPIO subsystem on its own cannot know what the hardware designer intended for a pin and while one may have the ability to make a pin begin driving an output, if it is actually expected to be an input this can lead to two devices both trying to drive a connected signal and irreparably damaging both devices!
To deal with this more complicated reality and the fact that GPIO attributes vary wildly, the operating system has a second concept which are called Dedicated Purpose I/Os (DPIO) which is designed to be used more directly by both software in the platform (e.g. fault management) or by other end-user applications.
A DPIO creates a named character device in /dev/dpio that has the following properties:
O_EXCL flag with
open(2). If a process has exclusive
access, then no one else will be able to open the device and read or write
to it. Similarly, if one or more processes have the device open, a request
for exclusive access will fail. In both cases
EBUSY is returned by the underlying kgpio
driver.The GPIO and DPIO subsystems are evolving interfaces in the operating system. To discover controllers, GPIOs, and DPIOs, privileged users can use the gpioadm(8) utility. This allows for getting and setting the attributes of GPIOs as well as creating and destroying DPIOs from GPIOs.
gpioadm(8) is implemented in terms of a system internal library called libxpio which can be used to manipulate and get information about GPIOs and DPIOs. This is itself built on-top of private user/kernel interfaces provided by the kgpio(4D) driver.
The DPIO interface is provided in
<sys/gpio/dpio.h>. All DPIOs
show up under /dev/dpio in the file system and the
character devices support the various
read(2) and
write(2) families of operations. Unlike
normal files, the DPIO character devices are not seekable. Both reads and
writes must be exactly 4 bytes in size. Reads return the
dpio_input_t enumeration which currently has two
values (though more may be added in the future):
DPIO_INPUT_LOWDPIO_INPUT_HIGHIt's worth noting that any hardware-specific changes to the input values such as polarity inversion control will have already been applied to the value. The actual thresholds for what constitutes a logic high and low are device dependent.
The write interface uses the dpio_output_t enumeration values which are:
DPIO_OUTPUT_LOWDPIO_OUTPUT_HIGHDPIO_OUTPUT_DISABLEDLike with reads, the voltage values are device dependent. In
addition, someone who has the device open may use the
DPIO_IOC_CUROUT ioctl to obtain information about
what the current output value is set to.
All DPIO interfaces are still evolving and subject to change.
Many complex SoCs (system-on-chip) have a way of switching what internal peripheral is actually using a specific pin. This peripheral may be a GPIO or it could be an entirely different device like a SPI controller, serial port, I2C, or more. At this time, the GPIO subsystem on its own does not manipulate this underlying mux and consumers of the platform will need to be aware of that. In the future, where appropriate for the controller, this subsystem will be integrated with this underlying mux to create a more holistic and useful experience.
GPIO providers are kernel drivers that interface with a hardware GPIO controller. They expose the attributes, which are passed around as a series of nvlist_t (libnvpair(3LIB)) structures. Attributes are either passed as an nvlist string or uint32 and then each attribute also contains optional metadata around the attribute's permissions and what values are possible for this particular GPIO. Attributes are allowed to vary from GPIO to GPIO. libxpio provides logic to translate anything that isn't in a string-form into something that is human-readable. This was done to allow for providers and programmatic interfaces to work in a more natural way (e.g. using enumerations and other numeric values) while still providing consumers something useful to use.
The core kernel GPIO driver, kgpio(4D), takes care of dealing with the traditional character device interfaces, minor nodes, and all of the logic around creating, destroying, and managing DPIOs. This in turn allows the GPIO provider drivers to be simpler and focus on the interface to hardware.
poll(2), read(2), write(2), port_get(3C), libnvpair(3LIB), kgpio(4D), gpioadm(8), ldi_open_by_name(9F)
| September 17, 2022 | OmniOS |