How UEFI Drivers Interface with GPIO Controllers

This article explores how Unified Extensible Firmware Interface (UEFI) drivers interact with platform-specific General Purpose Input/Output (GPIO) controllers. It covers the architectural separation between platform-independent code and silicon-specific hardware, the role of custom and standardized firmware protocols, direct register manipulation via Memory-Mapped I/O (MMIO), and the eventual handover of GPIO pin states and descriptors to the operating system through ACPI tables.

Architectural Hierarchy in EDK II

In standard UEFI implementations, such as TianoCore EDK II, the firmware isolates hardware-agnostic logic from silicon-specific implementations. The architecture divides hardware interaction across distinct firmware phases, primarily the Pre-EFI Initialization (PEI) and Driver Execution Environment (DXE) phases.

Platform-specific GPIO controllers reside on the system-on-chip (SoC) or platform controller hub (PCH). Because every silicon vendor (such as Intel, AMD, or ARM-based SoC manufacturers) designs their GPIO register layouts, pad multiplexing, and interrupt banks differently, the UEFI core cannot interact with these pins directly through a universal specification. Instead, silicon initialization code provides a driver that encapsulates these hardware nuances, exposing standard or semi-standard interfaces to consumer drivers.

Protocols and Architectural Abstraction

In the DXE phase, a silicon-specific GPIO driver publishes an interface called an EFI_PROTOCOL. While the UEFI specification does not mandate a universal GPIO protocol, vendors define standard interfaces (often designated as EFI_GPIO_PROTOCOL or vendor-specific variants like PCH_GPIO_PROTOCOL).

Consumer drivers—such as those controlling panel backlights, I2C bus expanders, TPM chips, or discrete power-delivery circuits—locate this protocol using the gBS->LocateProtocol() boot service. The protocol function table exposes platform-agnostic APIs to manipulate pins, including:

  • Pin Direction Configuration: Setting pins to input, output, or alternative function modes.
  • State Manipulation: Driving pins high or low (SetPull(), WritePin()).
  • State Reading: Polling current pin levels (ReadPin()).
  • Multiplexing (Pinmux): Assigning specific controller functions (like UART, SPI, or I2C) to physical pads.
  • Interrupt and Wake Routing: Configuring electrical interrupt triggers and routing events to System Management Interrupts (SMI) or advanced configuration interfaces.

Memory-Mapped I/O (MMIO) and Register Access

Beneath the protocol layer, the silicon-specific driver interacts directly with the GPIO controller hardware using Memory-Mapped I/O (MMIO).

During early boot, the firmware initializes base address registers (BARs) for the GPIO block. The driver uses platform-level I/O services—such as EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL or direct CPU memory access primitives—to read and write to pad configuration registers. These operations typically require:

  1. Pad Ownership and Protection: Unlocking register banks that prevent unauthorized modifications during runtime.
  2. Configuration Masking: Modifying directional bits, slew rates, internal pull-up/pull-down resistors, and input inversion settings without disrupting adjacent pin definitions in the same register bank.
  3. Synchronization and Fencing: Utilizing memory barriers to ensure register writes complete in order, preventing race conditions during time-sensitive peripheral resets.

Table-Driven Static Configuration

Most modern platforms avoid hardcoding pin transitions into procedural driver code. Instead, platform engineers define pin states in declarative data tables during firmware compilation.

The platform board package (Board DXE/PEI driver) provides a platform-specific pin configuration table specifying every pad's required reset state, electrical characteristics, and ownership flags (Host, CSME/PSP, or EC). The silicon driver iterates through this table during PEI or DXE, writing configuration blocks sequentially to place all pins into a known, safe electrical state before secondary peripheral drivers execute.

Handoff to the Operating System via ACPI

UEFI drivers maintain authority over GPIO controllers only until ExitBootServices() is invoked. To allow the operating system to interface with platform GPIOs, UEFI generates or patches ACPI tables during the boot sequence:

  • Differentiated System Description Table (DSDT): UEFI injects GPIO controllers as ACPI devices (PNP0C40 or vendor-specific hardware IDs).
  • Resource Descriptors: Peripheral devices declared in ACPI describe their GPIO pin connections via GpioIo() and GpioInt() connection descriptors, indicating pin numbers and electrical parameters defined during the UEFI boot phase.
  • GPIO Operation Regions (OpRegion): UEFI can define custom ACPI address spaces, allowing ACPI control methods (_OSC, _DSM, or power resource transitions) to evaluate and change pin states using native OS GPIO drivers after boot services terminate.