ACPI 中文文档ACPI 中文文档
首页
第 1 章
第 2 章
第 3 章
第 4 章
第 5 章
第 6 章
第 7 章
第 8 章
第 9 章
第 10 章
第 11 章
第 12 章
第 13 章
第 14 章
第 15 章
第 16 章
第 17 章
第 18 章
第 19 章
第 20 章
第 21 章
附录 A
首页
第 1 章
第 2 章
第 3 章
第 4 章
第 5 章
第 6 章
第 7 章
第 8 章
第 9 章
第 10 章
第 11 章
第 12 章
第 13 章
第 14 章
第 15 章
第 16 章
第 17 章
第 18 章
第 19 章
第 20 章
第 21 章
附录 A
  • 第 13 章

    • 总览
    • 13.1. SMBus 概述
    • 13.2. 从 ASL 代码访问 SMBus
    • 13.3. 使用 SMBus 协议

13.2. 从 ASL 代码访问 SMBus

以下各节演示如何从 ASL 代码访问和使用 SMBus。

13.2.1. 声明 SMBus 主控制器对象

基于 EC 的 SMBus 1.0 兼容 HC 应按在 ACPI 命名空间中定义嵌入式控制器设备“在 ACPI 命名空间中定义嵌入式控制器 SMBus 主控制器”中所述的方式在 ACPI 命名空间中建模。下面给出了一个定义示例。使用 HID 值 “ACPI0001” 表明该 SMB-HC 是在嵌入式控制器上实现的,并使用通过嵌入式控制器的 SMBus 主控制器接口中定义的标准 SMBus 寄存器集。

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

基于 EC 的 SMBus 2.0 兼容主控制器应类似地按如下方式在命名空间中定义:

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

非基于 EC 的 SMB-HC 应以与基于 EC 的 SMBus HC 类似的方式进行建模。下面给出了一个定义示例。这些设备使用厂商特定的硬件标识符(HID)来指定 SMB-HC 的类型(不要使用 “ACPI0001” 或 “ACPI0005”)。使用厂商特定 HID 可使正确的软件被加载,以服务于该段的 SMBus 地址空间。

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

无论硬件类型如何,某个 OS 软件元素(例如 SMBus HC 驱动程序)都必须向 OSPM 注册,以支持为该段定义的所有 SMBus 操作区域。该软件通过在概念模型(例如 SMBus 地址空间)与物理模型(例如写/读寄存器的过程)之间进行转换,使本节定义的通用 SMBus 接口能够用于特定硬件实现。由于这种关联,SMBus 操作区域必须直接在相应 SMBus 设备的作用域内定义。

13.2.2. 声明 SMBus 设备

由 SMBus 规范 http://smbus.org/specs/ 定义的 SMBus 不是一种可枚举总线。因此,SMBus 1.0 兼容的 SMB-HC 驱动程序无法发现 SMBus 上的子设备并加载相应的设备驱动程序。因此,SMBus 1.0 兼容设备会像其他主板设备一样在 ACPI 命名空间中声明,并由 OSPM 进行枚举。

SMBus 2.0 规范增加了在总线上实现设备枚举的机制,同时保持与现有设备的兼容性。ACPI 为基于 EC 的 SMBus 2.0 兼容主控制器定义并关联了 HID 值 “ACPI0005”。当 SMBus 1.0 兼容设备在命名空间中声明于 SMBus 2.0 兼容主控制器之下时,OSPM 将对其进行枚举。

定义 ACPI 命名空间对象的责任(这些对象是 SMBus 2.0 兼容主控制器驱动程序枚举不可由总线枚举的设备所必需的)被交由智能电池系统实现者论坛负责。请参见上述链接中的 SMBus 规范。

从 ACPI 2.0 开始,使用 _ADR 将 SMBus 设备与其最低 SMBus 从设备地址相关联。

13.2.3. 声明 SMBus 操作区域

每个 SMBus 操作区域定义标识一个单独的 SMBus 从设备地址。仅对那些需要从 AML 访问的 SMBus 设备定义操作区域。与其他区域一样,SMBus 操作区域只能通过 Field 项访问(参见声明 SMBus 设备)。

该接口将每个 SMBus 设备建模为具有一个 256 字节的线性地址范围。该范围内的每个字节偏移对应一个单独的命令值(例如,字节偏移 0x12 等同于命令值 0x12),最多可有 256 个命令值。通过这种方式,SMBus 地址空间呈现为线性,并且可以采用与其他地址空间类型类似的方式进行处理。

OperationRegion 项的语法(来自OperationRegion(声明操作区域))如下所述。

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

其中:

  • RegionName 指定该从设备的名称(例如,“SBD0”)。

  • RegionSpace 必须设置为 SMBus(操作区域类型值 0x04)。

  • Offset 是一个字大小的值,用于指定目标设备的从设备地址和初始命令值偏移。从设备地址存储在高字节中,命令值偏移存储在低字节中。例如,对于一个位于从设备地址 0x42 且初始命令值偏移为零(0)的 SMBus 设备,应使用值 0x4200。

  • Length 对于初始命令值偏移为零(0)的区域,设置为 0x100(256),表示可能命令值的最大数量。对于具有非零偏移的区域,则使用这两个值的差值。例如,Offset 值为 0x4210 的区域,其对应的 Length 为 0xF0(0x100 减去 0x10)。

例如,智能电池子系统(如下图所示)由位于从设备地址 0x09 的智能电池充电器、位于从设备地址 0x0A 的智能电池系统管理器,以及位于从设备地址 0x0B 的一个或多个电池(复用)组成。(请注意,图 13-2 表示的是智能电池子系统的逻辑连接。智能电池和智能电池充电器的实际物理连接是通过智能电池系统管理器实现的。)所有设备都支持读/写字协议。电池还支持读/写块协议。

../_images/ACPI_Sys_Mgmt_Bus_Interface_Specification-3.png

图 13.2 智能电池子系统设备

以下 ASL 代码展示了如何使用 OperationRegion 项来描述这些 SMBus 设备:

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)
   :
}

请注意,本示例中的这些操作区域是在“拥有”该 EC-SMBus 设备的直接上下文中定义的。每个定义都对应一个独立的从地址(设备),并且恰好使用零(0)作为初始命令值偏移量。

13.2.4. 声明 SMBus 字段

与其他区域一样,SMBus 操作区域只能通过 Field 项访问。每个字段元素都分配有唯一的命令值,并表示目标 SMBus 设备上的一个虚拟寄存器。

Field 项的语法(摘自Event(声明事件同步对象))如下所述。

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

其中:

  • RegionName 指定先前为该设备定义的操作区域名称。

  • AccessType 必须设置为 BufferAcc。这表示对字段元素的访问将使用特定于区域的数据缓冲区。对于这种访问类型,字段处理程序并不知道数据缓冲区的内容,而其大小可以是任意的。当此类型的字段在操作中用作源参数时,它只会求值为一个缓冲区。然而,当用作目标时,该缓冲区会以双向方式传递,以允许从写操作返回数据。随后,被修改的缓冲区成为该操作的执行结果。这与通常情况下略有不同;通常情况下,执行结果与写入目标的值相同。请注意,源永远不会被更改,因为它可能是只读对象(请参见“声明和使用 SMBus 数据缓冲区”以及ASL 操作码项)。

  • LockRule 指示访问该操作区域是否需要获取 Global Lock 以进行同步。在固件可能访问 SMBus 的系统上,该字段应设置为 Lock;否则应设置为 NoLock。

  • UpdateRule 不适用于 SMBus 操作区域,因为每个虚拟寄存器都是整体访问的。对于所有 SMBus 字段定义,此字段都会被忽略。

SMBus 操作区域要求所有字段元素都按命令值粒度声明。这意味着在字段定义中,每个虚拟寄存器都不能进一步拆分为各个位。

对虚拟寄存器子部分的访问只能在字段定义之外完成。施加此限制既是为了简化 SMBus 接口,也是为了保持与 SMBus 规范定义的物理模型一致。

SMBus 协议在字段定义中使用 AccessAs 项分配给字段元素。该项的语法(摘自ASL 根项和次级项)如下所述。

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

其中:

  • AccessType 必须设置为 BufferAcc。

  • AccessAttribute 指示要分配给该项之后命令值的 SMBus 协议。有关 SMBus 协议类型及其取值列表,请参见SMBus 协议。

AccessAs 项必须作为字段定义中的第一项出现,以设置其后字段元素的初始 SMBus 协议。每个字段元素最多只能定义一种 SMBus 协议。对于单个命令值支持多种协议的设备,可以通过指定多个具有相同偏移量(命令值)的字段元素来建模,其中每个字段元素前都带有一个指定备用协议的 AccessAs 项。

例如,智能电池设备的命令值 0x08 处的寄存器(如下图所示)表示一个字值,用于指定电池温度(以开尔文为单位);而命令值 0x20 处的寄存器表示一个可变长度(0 到 32 字节)的字符串,用于指定电池制造公司的名称。

../_images/ACPI_Sys_Mgmt_Bus_Interface_Specification-4.png

图 13.3 智能电池设备虚拟寄存器

下面的 ASL 代码展示了如何使用 OperationRegion、Field、AccessAs 和 Offset 项来表示这些智能电池设备虚拟寄存器:

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]
}

请注意,命令值等同于字段元素的字节偏移量(例如,MFGA=0,RCAP=1,BTMP=8)。AccessAs 项指示每个命令值应使用哪种 SMBus 协议。

13.2.5. 声明和使用 SMBus 数据缓冲区

在 SMBus 事务中使用数据缓冲区,可使 AML 接收状态和值长度信息,同时也使 Process Call 协议的实现成为可能。如前所述,使用 BufferAcc 访问类型来向字段处理程序指示将使用特定于区域的数据缓冲区。

对于 SMBus 操作区域,该数据缓冲区定义为固定长度的 34 字节缓冲区;如果使用 “C” 风格的声明来表示,其模型如下:

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
}

其中:

  • Status(字节 0)指示给定 SMBus 事务的状态代码。更多信息请参见SMBus 状态代码。

  • Length(字节 1)指定数据缓冲区中有效数据的字节数。该字段的使用仅针对 Read/Write Block 协议定义,此时有效的 Length 值为 0 到 32。对于其他协议——其数据长度由协议隐含指定——该字段保留。

  • Data(字节 33-2)表示一个 32 字节缓冲区,是存储实际数据的位置。

例如,下面的 ASL 展示了如何使用 SMBus 数据缓冲区对智能电池设备执行事务。该代码基于“声明 SMBus 字段”中给出的 ASL 示例,其中列出了智能电池设备的操作区域和字段定义。

/* 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)
}

请注意,使用了 CreateField 基元来访问数据缓冲区的子元素(Status、Length 和 Data),其中 Data(字节 33-2)被“类型转换”为字(OB3)和块(OB4)两种数据类型。

上述示例演示了使用 Store() 操作符来调用一次 Read Block 事务,以获取电池制造商名称。对源操作数(MFGN)的求值结果是一个 34 字节缓冲区,该缓冲区由 Store() 复制到_目标_缓冲区(BUFF)。

捕获写操作的结果,例如检查状态代码,需要额外使用一个 Store() 操作符,如下所示。

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

请注意,外层的 Store() 会将 Write Block 事务的结果复制回 BUFF。这就是“声明 SMBus 字段”中所述 BufferAcc 双向性的本质。应当指出的是,保存(或解析)SMBus 写事务的结果并非必需,尽管这有助于确定事务的结果。

SMBus Process Call 协议由于只有目标操作数以双向方式传递,因此需要类似的语义。这些事务需要使用双重 Store() 语义,才能正确捕获返回结果。

Prev
13.1. SMBus 概述
Next
13.3. 使用 SMBus 协议