13.2. Accessing the SMBus from ASL Code

The following sections demonstrate how to access and use the SMBus from ASL code.

13.2.1. Declaring SMBus Host Controller Objects

EC-based SMBus 1.0-compatible HCs should be modeled in the ACPI namespace as described in Defining an Embedded Controller Device in ACPI Namespace , “Defining an Embedded Controller SMBus Host Controller in ACPI Namespace.” An example definition is given below. Using the HID value “ACPI0001” identifies that this SMB-HC is implemented on an embedded controller using the standard SMBus register set defined in SMBus Host Controller Interface via Embedded Controller.

Device (SMB0)
{
   Name(_HID, "ACPI0001") // EC-based SMBus 1.0 compatible Host Controller
   Name(_EC, 0x2030) // EC offset 0x20, query bit 0x30
      :
}

EC-based SMBus 2.0-compatible host controllers should be defined similarly in the namespace as follows:

Device (SMB0)
{
   Name(_HID, "ACPI0005") // EC-based SMBus 2.0 compatible Host Controller
   Name(_EC, 0x2030) // EC offset 0x20, query bit 0x30
      :
}

Non-EC-based SMB-HCs should be modeled in a manner similar to the EC-based SMBus HC. An example definition is given below. These devices use a vendor-specific hardware identifier (HID) to specify the type of SMB-HC (do not use “ACPI0001” or “ACPI0005”). Using a vendor-specific HID allows the correct software to be loaded to service this segment’s SMBus address space.

Device(SMB0)
{
   Name(_HID, "<vendor-specific hid>") // Vendor-Specific HID
      :
}

Regardless of the type of hardware, some OS software element (for example, the SMBus HC driver) must register with OSPM to support all SMBus operation regions defined for the segment. This software allows the generic SMBus interface defined in this section to be used on a specific hardware implementation by translating between the conceptual (for example, SMBus address space) and physical (for example, process of writing/reading registers) models. Because of this linkage, SMBus operation regions must be defined immediately within the scope of the corresponding SMBus device.

13.2.2. Declaring SMBus Devices

The SMBus, as defined by the SMBus Specifications <http://smbus.org/specs/>, is not an enumerable bus. As a result, an SMBus 1.0-compatible SMB-HC driver cannot discover child devices on the SMBus and load the appropriate corresponding device drivers. As such, SMBus 1.0-compatible devices are declared in the ACPI namespace, in like manner to other motherboard devices, and enumerated by OSPM.

The SMBus 2.0 specification adds mechanisms enabling device enumeration on the bus while providing compatibility with existing devices. ACPI defines and associates the “ACPI0005” HID value with an EC-based SMBus 2.0-compatible host controller. OSPM will enumerate SMBus 1.0-compatible devices when declared in the namespace under an SMBus 2.0-compatible host controller.

The responsibility for the definition of ACPI namespace objects, required by an SMBus 2.0-compatible host controller driver to enumerate non-bus-enumerable devices, is relegated to the Smart Battery System Implementers Forum. See the SMBus Specifications at the link mentioned above.

Starting in ACPI 2.0, _ADR is used to associate SMBus devices with their lowest SMBus slave address.

13.2.3. Declaring SMBus Operation Regions

Each SMBus operation region definition identifies a single SMBus slave address. Operation regions are defined only for those SMBus devices that need to be accessed from AML. As with other regions, SMBus operation regions are only accessible via the Field term (see Declaring SMBus Devices).

This interface models each SMBus device as having a 256-byte linear address range. Each byte offset within this range corresponds to a single command value (for example, byte offset 0x12 equates to command value 0x12), with a maximum of 256 command values. By doing this, SMBus address spaces appear linear and can be processed in a manner similar to the other address space types.

The syntax for the OperationRegion term (from OperationRegion (Declare Operation Region)) is described below.

OperationRegion (
   RegionName,             // NameString
   RegionSpace,            // RegionSpaceKeyword
   Offset,                 // TermArg=>Integer
   Length                  // TermArg=>Integer
)

Where:

  • RegionName specifies a name for this slave device (for example, “SBD0”).

  • RegionSpace must be set to SMBus (operation region type value 0x04).

  • Offset is a word-sized value specifying the slave address and initial command value offset for the target device. The slave address is stored in the high byte and the command value offset is stored in the low byte. For example, the value 0x4200 would be used for an SMBus device residing at slave address 0x42 with an initial command value offset of zero (0).

  • Length is set to the 0x100 (256), representing the maximum number of possible command values, for regions with an initial command value offset of zero (0). The difference of these two values is used for regions with non-zero offsets. For example, a region with an Offset value of 0x4210 would have a corresponding Length of 0xF0 (0x100 minus 0x10).

For example, the Smart Battery Subsystem (illustrated below) consists of the Smart Battery Charger at slave address 0x09, the Smart Battery System Manager at slave address 0x0A, and one or more batteries (multiplexed) at slave address 0x0B. (Notice that Figure 13-2 represents the logical connection of a Smart Battery Subsystem. The actual physical connections of the Smart Battery(s) and the Smart Battery Charger are made through the Smart Battery System Manager.) All devices support the Read/Write Word protocol. Batteries also support the Read/Write Block protocol.

../_images/ACPI_Sys_Mgmt_Bus_Interface_Specification-3.png

Fig. 13.2 Smart Battery Subsystem Devices

The following ASL code shows the use of the OperationRegion term to describe these SMBus devices:

Device (SMB0)
{
   Name(_HID, "ACPI0001") // EC-SMBus Host Controller
   Name(_EC, 0x2030) // EC offset 0x20, query bit 0x30

OperationRegion(SBC0, SMBus, 0x0900, 0x100)      // Smart Battery Charger
OperationRegion(SBS0, SMBus, 0x0A00, 0x100)      // Smart Battery Selector
OperationRegion(SBD0, SMBus, 0x0B00, 0x100)      // Smart Battery Device(s)
   :
}

Notice that these operation regions in this example are defined within the immediate context of the ‘owning’ EC-SMBus device. Each definition corresponds to a separate slave address (device), and happens to use an initial command value offset of zero (0).

13.2.4. Declaring SMBus Fields

As with other regions, SMBus operation regions are only accessible via the Field term. Each field element is assigned a unique command value and represents a virtual register on the targeted SMBus device.

The syntax for the Field term (from Event (Declare Event Synchronization Object)) is described below.

Field(
   RegionName,           // NameString=>OperationRegion
   AccessType,           // AccessTypeKeyword
   LockRule,             // LockRuleKeyword
   UpdateRule            // UpdateRuleKeyword - *ignored*
) {FieldUnitList}

Where:

  • RegionName specifies the operation region name previously defined for the device.

  • AccessType must be set to BufferAcc. This indicates that access to field elements will be done using a region-specific data buffer. For this access type, the field handler is not aware of the data buffer’s contents which may be of any size. When a field of this type is used as the source argument in an operation it simply evaluates to a buffer. When used as the destination, however, the buffer is passed bi-directionally to allow data to be returned from write operations. The modified buffer then becomes the execution result of that operation. This is slightly different than the normal case in which the execution result is the same as the value written to the destination. Note that the source is never changed, since it could be a read only object (see Declaring and Using an SMBus Data Buffer and ASL Opcode Terms).

  • LockRule indicates if access to this operation region requires acquisition of the Global Lock for synchronization. This field should be set to Lock on system with firmware that may access the SMBus, and NoLock otherwise.

  • UpdateRule is not applicable to SMBus operation regions since each virtual register is accessed in its entirety. This field is ignored for all SMBus field definitions.

SMBus operation regions require that all field elements be declared at command value granularity. This means that each virtual register cannot be broken down to its individual bits within the field definition.

Access to sub-portions of virtual registers can be done only outside of the field definition. This limitation is imposed both to simplify the SMBus interface and to maintain consistency with the physical model defined by the SMBus specification.

SMBus protocols are assigned to field elements using the AccessAs term within the field definition. The syntax for this term (from ASL Root and Secondary Terms) is described below.

AccessAs(
   AccessType, //AccessTypeKeyword
   AccessAttribute //Nothing \| ByteConst \| AccessAttribKeyword
)

Where:

  • AccessType must be set to BufferAcc.

  • AccessAttribute indicates the SMBus protocol to assign to command values that follow this term. See SMBus Protocols for a listing of the SMBus protocol types and values.

An AccessAs term must appear as the first entry in a field definition to set the initial SMBus protocol for the field elements that follow. A maximum of one SMBus protocol may be defined for each field element. Devices supporting multiple protocols for a single command value can be modeled by specifying multiple field elements with the same offset (command value), where each field element is preceded by an AccessAs term specifying an alternate protocol.

For example, the register at command value 0x08 for a Smart Battery device (illustrated below) represents a word value specifying the battery temperature (in degrees Kelvin), while the register at command value 0x20 represents a variable-length (0 to 32 bytes) character string specifying the name of the company that manufactured the battery.

../_images/ACPI_Sys_Mgmt_Bus_Interface_Specification-4.png

Fig. 13.3 Smart Battery Device Virtual Registers

The following ASL code shows the use of the OperationRegion, Field, AccessAs, and Offset terms to represent these Smart Battery device virtual registers:

OperationRegion(SBD0, SMBus, 0x0B00, 0x0100)
Field(SBD0, BufferAcc, NoLock, Preserve)
{
   AccessAs(BufferAcc, SMBWord)   // Use the SMBWord protocol for the following...
   MFGA, 8,                       // ManufacturerAccess() [command value 0x00]
   RCAP, 8,                       // RemainingCapacityAlarm() [command value 0x01]
   Offset(0x08)                   // Skip to command value 0x08...
   BTMP, 8,                       // Temperature() [command value 0x08]
   Offset(0x20)                   // Skip to command value 0x20...
   AccessAs(BufferAcc, SMBBlock)  // Use the SMBBlock protocol for the following...
   MFGN, 8,                       // ManufacturerName() [command value 0x20]
   DEVN, 8                        // DeviceName() [command value 0x21]
}

Notice that command values are equivalent to the field element’s byte offset (for example, MFGA=0, RCAP=1, BTMP=8). The AccessAs term indicates which SMBus protocol to use for each command value.

13.2.5. Declaring and Using an SMBus Data Buffer

The use of a data buffer for SMBus transactions allows AML to receive status and data length values, as well as making it possible to implement the Process Call protocol. As previously mentioned, the BufferAcc access type is used to indicate to the field handler that a region-specific data buffer will be used.

For SMBus operation regions, this data buffer is defined as a fixed-length 34-byte buffer that, if represented using a ‘C’-styled declaration, would be modeled as follows:

typedef struct
{
   BYTE Status;               // Byte 0 of the data buffer
   BYTE Length;               // Byte 1 of the data buffer
   BYTE[32] Data;             // Bytes 2 through 33 of the data buffer
}

Where:

  • Status (byte 0) indicates the status code of a given SMBus transaction. See SMBus Status Codes for more information.

  • Length (byte 1) specifies the number of bytes of valid data that exists in the data buffer. Use of this field is only defined for the Read/Write Block protocol, where valid Length values are 0 through 32. For other protocols–where the data length is implied by the protocol–this field is reserved.

  • Data (bytes 33-2) represents a 32-byte buffer, and is the location where actual data is stored.

For example, the following ASL shows the use of the SMBus data buffer for performing transactions to a Smart Battery device. This code is based on the example ASL presented in Declaring SMBus Fields which lists the operation region and field definitions for the Smart Battery device.

/* Create the SMBus data buffer */
Name(BUFF, Buffer(34){})            // Create SMBus data buffer as BUFF
CreateByteField(BUFF, 0x00, OB1)    // OB1 = Status (Byte)
CreateByteField(BUFF, 0x01, OB2)    // OB2 = Length (Byte)
CreateWordField(BUFF, 0x02, OB3)    // OB3 = Data (Word - Bytes 2 & 3)
CreateField(BUFF, 0x10, 256, OB4)   // OB4 = Data (Block - Bytes 2-33)

/* Read the battery temperature */
Store(BTMP, BUFF) // Invoke Read Word transaction
If(LEqual(OB1, 0x00)) // Successful?
{
                                    // OB3 = Battery temperature in 1/10th degrees Kelvin
}

/* Read the battery manufacturer name */
Store(MFGN, BUFF)                   // Invoke Read Block transaction
If(LEqual(OB1, 0x00))               // Successful?
{
                                    // OB2 = Length of the manufacturer name
                                    // OB4 = Manufacturer name (as a counted string)
}

Notice the use of the CreateField primitives to access the data buffer’s sub-elements (Status, Length, and Data), where Data (bytes 33-2) is ‘typecast’ as both word (OB3) and block (OB4) data.

The example above demonstrates the use of the Store() operator to invoke a Read Block transaction to obtain the name of the battery manufacturer. Evaluation of the source operand (MFGN) results in a 34-byte buffer that gets copied by Store() to the destination buffer (BUFF).

Capturing the results of a write operation, for example to check the status code, requires an additional Store() operator, as shown below.

Store(Store(BUFF, MFGN), BUFF)      // Invoke Write Block transaction
If(LEqual(OB1, 0x00)) {...}         // Transaction successful?

Note that the outer Store() copies the results of the Write Block transaction back into BUFF. This is the nature of BufferAcc’s bi-directionality described in Declaring SMBus Fields. It should be noted that storing (or parsing) the result of an SMBus Write transaction is not required although useful for ascertaining the outcome of a transaction.

SMBus Process Call protocols require similar semantics due to the fact that only destination operands are passed bi-directionally. These transactions require the use of the double-Store() semantics to properly capture the return results.