This article is the first in a series describing the changes in the Platform Initialization (PI) 1.3 specification. The PI specification is like the unheralded younger brother of the UEFI specification. From the very beginning it was a requirement that PI implementations be able to produce UEFI, but it was also a requirement that UEFI drivers and applications and OS loaders not depend on the PI specification. If something was really needed for UEFI, it would get promoted (yes, that is the word used) from the PI specification. Why? Because there have been (and are) implementations of UEFI which are not built on top of the tianocore.org EDK1 or EDK2 implementations or even Intel's older Platfrom Innovation Framework.
It was named the Platform Initialization (PI) specification because, in the UEFI 2.0 specification (and the earlier EFI 1.x specifications), one of the block diagrams of UEFI had a big blank box labeled (you guessed it): "Platform Initialization" UEFI really deals with booting. Yes, yes, there's a lot of other stuff around user interface (HII) and security and networking, but it is all about finding the right boot device and loading the OS. If you are not a boot device (or a video device or a keyboard), you don't really get a lot of respect in UEFI. That is PI. So, what's in there? Well, there's memory controllers, GPIOs, system management mode (SMM), PCI root bridges, super I/O controllers, embedded controllers, and yes, I2C and SMBus. All in the PI specification.
I2C didn't get a lot of respect either in the UEFI world, ever since Intel began promoting the smarter, enumerable version, called SMBus. But it turns out that, as a simple, low-cost, low speed, low-power bus, it works well for controlling on-the-motherboard devices, like touch panels, MEMS sensors, small EEPROMs and other devices with relatively low data rates. Also, SMBus didn't really like multiple speed devices.
Within PI, SMBus suffered from only have a host controller protocol, but it was never extended out to a true driver stack like, say, USB or PCI. Sad. If you want to see how its really done, look at my presentation from the UEFI plugfest back in 2011.
But back to I2C. The following diagram shows the typical driver stack. It looks very similar to the typical UEFI driver stack, with a host controller protocol and an I/O protocol. But after that it gets a bit strange: what are the enumerate, bus configuration management and master protocol?
First, it is important to understand the I2C is not really enumerable. You can't poke at some register and discover that a device is present. At least not reliably, from a bus driver perspective. USB and PCI and SMBus are examples of enumerable buses. So, instead, the I2C driver stack relies on a platform driver to produce the I2C Enumerate protocol to return back a list of devices actually present on the platform.
Second, since it is possible for the I2C bus to be one of several different configurations, it is important that the bus be placed in the right configuration before talking to a specific device. For example, if the bus speed must be changed, or a multiplexer must be set so that I2C devices are actually connected to the controller. That control is provided by the I2C Bus Configuration Management protocol.
Third, the host controller support is divided into two pieces: the Master protocol and the Host protocol. In general, the device driver's use the Host protocol to queue an I2C transaction. The Master protocol is used when it is necessary to go out of order and send an I2C command. This happens, for example, when the platform driver needs to send an command to a multiplexer or bus clock device before an I2C command is sent to a device.
With the I2C protocols, the PI 1.3 specification gives a driver stack so that you can write a device driver for an I2C device that works on any platform. But this is only for DXE. In PEI, only the Master capabilities are available through the I2C Master PPI.