Legacy EC Interface
ACPI specification has a definition for an embedded controller, however this implementation is tied very closely to the eSPI bus and x86 architecture.
The following is an example of legacy EC interface definition from ACPI
11.7. Thermal Zone Examples — ACPI Specification 6.4 documentation
#![allow(unused)] fn main() { Scope(\\_SB.PCI0.ISA0) { Device(EC0) { Name(_HID, EISAID("PNP0C09")) // ID for this EC // current resource description for this EC Name(_CRS, ResourceTemplate() { IO(Decode16,0x62,0x62,0,1) IO(Decode16,0x66,0x66,0,1) }) Name(_GPE, 0) // GPE index for this EC // create EC's region and field for thermal support OperationRegion(EC0, EmbeddedControl, 0, 0xFF) Field(EC0, ByteAcc, Lock, Preserve) { MODE, 1, // thermal policy (quiet/perform) FAN, 1, // fan power (on/off) , 6, // reserved TMP, 16, // current temp AC0, 16, // active cooling temp (fan high) , 16, // reserved PSV, 16, // passive cooling temp HOT 16, // critical S4 temp CRT, 16 // critical temp } // following is a method that OSPM will schedule after // it receives an SCI and queries the EC to receive value 7 Method(_Q07) { Notify (\\_SB.PCI0.ISA0.EC0.TZ0, 0x80) } // end of Notify method // fan cooling on/off - engaged at AC0 temp PowerResource(PFAN, 0, 0) { Method(_STA) { Return (\\_SB.PCI0.ISA0.EC0.FAN) } // check power state Method(_ON) { Store (One, \\\\_SB.PCI0.ISA0.EC0.FAN) } // turn on fan Method(_OFF) { Store ( Zero, \\\\_SB.PCI0.ISA0.EC0.FAN) }// turn off fan } // Create FAN device object Device (FAN) { // Device ID for the FAN Name(_HID, EISAID("PNP0C0B")) // list power resource for the fan Name(_PR0, Package(){PFAN}) } // create a thermal zone ThermalZone (TZ0) { Method(_TMP) { Return (\\_SB.PCI0.ISA0.EC0.TMP )} // get current temp Method(_AC0) { Return (\\_SB.PCI0.ISA0.EC0.AC0) } // fan high temp Name(_AL0, Package(){\\_SB.PCI0.ISA0.EC0.FAN}) // fan is act cool dev Method(_PSV) { Return (\\_SB.PCI0.ISA0.EC0.PSV) } // passive cooling temp Name(_PSL, Package (){\\_SB.CPU0}) // passive cooling devices Method(_HOT) { Return (\\_SB.PCI0.ISA0.EC0.HOT) } // get critical S4 temp Method(_CRT) { Return (\\_SB.PCI0.ISA0.EC0.CRT) } // get critical temp Method(_SCP, 1) { Store (Arg1, \\\\_SB.PCI0.ISA0.EC0.MODE) } // set cooling mode Name(_TSP, 150) // passive sampling = 15 sec Name(_TZP, 0) // polling not required Name (_STR, Unicode ("System thermal zone")) } // end of TZ0 } // end of ECO } // end of \\\\_SB.PCI0.ISA0 scope- }
On platforms that do not support IO port access there is an option to define MMIO regions to simulate the IO port transactions.
In the above example you can see that the operation region directly maps to features on the EC and you can change the EC behavior by writing to a byte in the region or reading the latest data from the EC.
For a system with the EC connected via eSPI and that needs a simple non-secure interface to the EC the above mapping works very well and keeps the code simple. The eSPI protocol itself has details on port accesses and uses the peripheral channel to easily read/write memory mapped regions.
As the EC features evolve there are several requirements that do no work well with this interface:
-
Different buses such as I3C, SPI, UART target a packet request/response rather than a memory mapped interface
-
Protected or restricted access and validation of request/response
-
Firmware update, large data driven requests that require larger data response the 256-byte region is limited
-
Discoverability of features available and OEM customizations
-
Out of order completion of requests, concurrency, routing and priority handling
As we try to address these limitations and move to a more packet based protocol described in this document. The following section covers details on how to adopt existing operation region to new ACPI functionality.
Adopting EC Operation Region
The new OS frameworks such as MPTF still use ACPI methods as primary interface. Instead of defining devices such as FAN or ThermalZone in the EC region you can simply define the EC region itself and then map all the other ACPI functions to operate on this region. This will allow you to maintain backwards compatibility with existing EC definitions.
#![allow(unused)] fn main() { Device(EC0) { Name(_HID, EISAID("PNP0C09")) // ID for this EC // current resource description for this EC Name(_CRS, ResourceTemplate() { IO(Decode16,0x62,0x62,0,1) IO(Decode16,0x66,0x66,0,1) }) // create EC's region and field for thermal support OperationRegion(EC0, EmbeddedControl, 0, 0xFF) Field(EC0, ByteAcc, Lock, Preserve) { MODE, 1, // thermal policy (quiet/perform) FAN, 1, // fan power (on/off) , 6, // reserved TMP, 16, // current temp AC0, 16, // active cooling temp (fan high) , 16, // reserved PSV, 16, // passive cooling temp HOT 16, // critical S4 temp CRT, 16 // critical temp } } Device(SKIN) { Name(_HID, "MSFT000A") // New MPTF HID Temperature Device Method(_TMP, 0x0, Serialized) { Return( \\_SB.PCI0.ISA0.EC0.TMP) } } }
For more complicated functions that take a package some of the data may be constructed within ACPI and some of the data pulled from the OperationRegion. For example BIX for battery information may have a combination of static and dynamic data like this:
#![allow(unused)] fn main() { Method (_BIX) { Name (BAT0, Package (0x12) { 0x01, // Revision 0x02, // Power Unit 0x03, // Design Capacity \\_SB.PCI0.ISA0.EC0.BFCC, // Last Full Charge Capacity 0x05, // Battery Technology 0x06, // Design Voltage 0x07, // Design capacity of Warning 0x08, // Design Capacity of Low \\_SB.PCI0.ISA0.EC0.BCYL, // Cycle Count 0x0A, // Measurement Accuracy 0x0B, // Max Sampling Time 0x0C, // Min Sampling Time 0x0D, // Max Averaging Interval 0x0E, // Min Averaging Interval 0x0F, // Battery Capacity Granularity 1 0x10, // Battery Capacity Granularity 2 "Model123", // Model Number "Serial456", // Serial Number "Li-Ion", // Battery Type "OEMName" // OEM Information }) Return(BAT0) } }
Limitations for using Legacy EC
Before using the Legacy EC definition OEM’s should be aware of several use cases that may limit you ability to use it.
ACPI support for eSPI master
In the case of Legacy EC the communication to the EC is accomplished directly by the ACPI driver using PORT IO and eSPI Peripheral Bus commands. On ARM platforms there is no PORT IO and these must be substituted with MMIO regions. The ACPI driver needs changes to support MMIO which is being evaluated and support is not yet available. Some Silicon Vendors also do not implement the full eSPI specification and as such the ACPI driver cannot handle all the communication needs. On these platforms using Legacy EC interface is not an option.
Security of eSPI bus
When non-secure world is given access to the eSPI bus it can send commands to device on that bus. Some HW designs have the TPM or SPINOR on the same physical bus as the EC. On these designs allowing non-secure world to directly sends commands to EC can break the security requirements of other devices on the bus. In these cases the eSPI communication must be done in the secure world over FF-A as covered in this document and not use the Legacy EC channel. Since non-secure world has complete access to the EC operation region there is no chance for encryption of data. All data in the operation region is considered non-secure.
Functional limitations of Legacy EC
The peripheral region that is mapped in the Legacy EC in ACPI is limited to 256 bytes and notification events to the ones that are defined and handled in ACPI driver. To create custom solutions, send large packets or support encryption of data the Legacy EC interface has limitations in this area.