Note: Vendor ACPI Driver on Windows

之前寫了一些 ACPI Driver 相關的紀錄, 最近看到USB Type C connector for Windows 10 如果不做PD State Machine,下面也需要ACPI Driver 去協調 MCU/EC 所以整理一下手上有的資料 順便重新整理一下網路上很多消失的檔案

ACPIDriver Vista — 這個是Microsoft 最早提供的文件,不過根據實際經驗應該Windows XP 就支援這些功能
ACPI in Vista — 這是早期 WinHEC 2006 的 Presatations
BIOS implement of UCSI — Intel 這是Intel 講如何實作USB Type C Connector System Interface

older WDM/DDK Sample from Windows 2000

這邊提供實際原始碼的實作內容

Older WDM driver implement – 實作了Customer GPIO Button/Indicator LED, 應該是 Intel 用來Demo MID (Mobile Internal Device)做的
Current WDF Driver implement for UCSI - 這就是Microsoft 實作UCSI 的參考Driver了 可以搭配Intel 文件跟 Microsoft 網站資料一起看

下面是想更了解UCSI可以參考的資料
https://www.usb.org/developers/presentations/  — 2017 USB Developer Days  in Taipei

Update:
Linux 下的實作也有 Intel 提交的標準
https://github.com/torvalds/linux/tree/master/drivers/usb/typec/ucsi
所以盡可能透過在使用ACPI/ASL implement 去做這個功能,這樣Windows/Linux 下都有inbox driver 不用另外提供特殊的 customization driver
不過要透過標準UCSI 有一個地方考慮的是成本, 標準UCSI 界面是由 ACPI + EC + PD Controller 構成的,需要付出比較多的成本,目前已經有一個新的方式透過提供軟體的TCPM 取代PD Controller 如下圖 這個架構仍然需要一個MCU 去控制Type C 的界面行為, 系統透過I2C之類的下PD Policy 的行為給MCU

TCPCx

ref. https://www.mail-archive.com/linux-usb@vger.kernel.org/msg92179.html

廣告

Note: Intel defined an ACPI _DSM for Android power button event on x86 platform

_DSM Parameters
Arg0(Buffer) : UUID : “9c355bcb-35fa-44f7-8a67-447359c36a03″
Arg1(Integer): Revision: 0
Arg2(Integer): Function Index :
0: PWRB_PROBE, detect support power button state method
1: PWRB_REGISTER, enable/register Power button release notify
2: PWRB_LEVEL, get current level of power button
Arg3(package): NULL

Return of Function index
Function 0: PWRB_PROBE
Type: Buffer,
return a bitmask of supported functions as a buffer. Return a failure here as 0:
method not present or not function correctly means “no functions support"

bitmask:
bit 0: supported PWRB_REGISTER(DSM notify)
bit 1: supported PWRB_LEVEL (DSM polling)
Just need support one method, if all support OS driver will use DSM notify method.

Function 1: PWRB_REGISTER
Type: Integer,
0 is success register a support control method power button device.
Notify(PWRB_Obj, 0x80) // 0x80 for press state
Notify(PWRB_Obj, 0xC0) // 0xC0 for release state

Function 2: PWRB_LEVEL
Type: Integer,
1 or 0,  return 1 when press button , others return 0

ref. https://github.com/01org/ProductionKernelQuilts/blob/master/uefi/cht-m1stable/patches/0003-acpi-button-Power-button-release-implementation-via-.patch

 

 reference implement 
 Device (PWRB)
            {
                Name (_HID, EisaId ("PNP0C0C") /* Power Button Device */)  // _HID: Hardware ID
                Name (PBST, One)
                Name (UPPS, Zero)
                Name (PBLV, Zero)
                Method (PKG2, 2, Serialized)
                {
                    Name (PKG, Package (0x02)
                    {
                        Zero, 
                        Zero
                    })
                    PKG [Zero] = Arg0
                    PKG [One] = Arg1
                    Return (PKG) /* \_SB_.PWRB.PKG2.PKG_ */
                }

                Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
                {
                    Name (GPEB, Zero)
                    If (PPBG != Zero)
                    {
                        GPEB = GGPE (PPBG)
                        Return (PKG2 (GPEB, 0x04))
                    }

                    Return (Package (0x02)
                    {
                        0x1E, 
                        0x04
                    })
                }

                Method (_STA, 0, NotSerialized)  // _STA: Status
                {
                    If ((ECON == One) && PBST)
                    {
                        Return (0x0F)
                    }

                    Return (Zero)
                }

                Method (PBUP, 0, NotSerialized)
                {
                    If (UPPS)
                    {
                        Notify (PWRB, 0xC0) // Hardware-Specific
                    }
                }

                Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
                {
                    Name (_T_0, Zero)  // _T_x: Emitted by ASL Compiler
                    If (Arg0 == ToUUID ("9c355bcb-35fa-44f7-8a67-447359c36a03"))
                    {
                        If (Zero == ToInteger (Arg1))
                        {
                            While (One)
                            {
                                _T_0 = ToInteger (Arg2)
                                If (_T_0 == Zero)
                                {
                                    Return (Buffer (One)
                                    {
                                         0x07                                             /* . */
                                    })
                                }
                                ElseIf (_T_0 == One)
                                {
                                    UPPS = One
                                    ^^PCI0.LPCB.H_EC.ECMD (0x74)
                                    ^^PCI0.LPCB.H_EC.ECWT (One, RefOf (^^PCI0.LPCB.H_EC.PB10))
                                    Return (Zero)
                                }
                                ElseIf (_T_0 == 0x02)
                                {
                                    If (UPPS)
                                    {
                                        If (!PBLV)
                                        {
                                            Return (Zero)
                                        }
                                        Else
                                        {
                                            Return (One)
                                        }
                                    }
                                    ElseIf (^^PCI0.LPCB.PRBL)
                                    {
                                        Return (Zero)
                                    }
                                    Else
                                    {
                                        Return (One)
                                    }
                                }

                                Break
                            }
                        }
                    }

                    Return (Buffer (One)
                    {
                         0x00                                             /* . */
                    })
                }
            }

Note: ACPI 5.0 introduction Hardware-reduced ACPI

ACPI 從 5.0 開始支援非 x86 系統, 如現在最熱門的ARM, 為此他必須移除本來x86系統下由Intel 主導的HW相關設計, 如原本的ACPI Controller 的 GPE 區塊, ACPI 規範稱此為 Hardward-reduced ACPI, 可以看出這是Microsoft為了讓 Windows 8 可以跨x86 & ARM 兩種不同平台的努力(由規格中的提案人可得知, MSFT-0001 HW-reduced ACPI, 另外可以該提案後的影響章節直接快速定位到想要了解的部分)

下面是 3.11.1的內容

ACPI offers an alternative platform interface model that removes ACPI hardware requirements for platforms that do not implement the PC Architecture. In the Hardware-reduced ACPI model, the Fixed hardware interface requirements of Chapter 4 are removed, and Generic hardware interfaces are used instead. This provides the level of flexibility needed to innovate and differentiate in low-power hardware designs while enabling support by multiple Operating Systems.

  • UEFI firmware interface for boot (Legacy BIOS is not supported).
  • Boot in ACPI mode only (ACPI Enable, ACPI Disable, SMI_CMD and Legacy mode are not
    supported)
  • No hardware resource sharing between OSPM and other asynchronous operating environments, such as UEFI Runtime Services or System Management Mode. (The Global Lock is not supported)
  • No dependence on OS-support for maintaining cache coherency across processor sleep states (Bus Master Reload and Arbiter Disable are not supported)

由上可以看出 UEFI + ACPI mode only 可以看出已經拋棄x86 PC 相容的包袱(沒有LegacyBIOS ACPI 必須在 E/F Segement的要求, ARM 本身也沒有 SMI的設計),  沒有SM/Runtime Services 主要應該MSFT不想要系統中還有一個可以讓 OS有不知不覺的管理層, 這樣對MSFT來說增加了被Rookit的風險, 最後應該可以有更理想的電源管理方式

Hardward-reduced ACPI 主要影響的章節

  • 3.11.x,
  • 4, 4.1.x, 4.3.7,
  • 5.2.9, 5.2.9.1,
  • 6.4.2.1, 6.4.3.6,
  • 7.2.11, 7.3.4,
  • 9.6,
  • 12, 12.1, 12.6, 12.11, 12.11.1,
  • 15, 15.1.x, 15.3, 15.3.1.x,
  • 18.5.55, 18.5.57

Note: About Integrated USB Device & System Fund 0200 WHQL item

Win7 有個測試項目 Single computer Display Object item (SystemFund-0200) , 專門測試系統內建的周邊是否有正確報告. 整合式的周邊因為不能被使用者任意移除所以不會出現在 Device & Printer 的ICON 列表中, 或者是出現在可以安全移除的裝置中!

一般BIOS 工程師會遇到的是 SATA & USB port, SATA 會有對應的控制 bit  可以設定, USB  則要透過 ACPI 去宣告 port 的屬性

Microsoft 已經提供有下列一些文件解釋

要補註的是 ACPI Spec. 應該要參考 4.x (Page 362 at 4.0a), 主要差異在於3.x中提到的 Integrated HUB 的Device Object 已經移除, 如果ASL code中有這一層, 實際上測試是錯誤的
非正式的做法是 _UPC 傳回的是 unconnectable
目前正式做法就是同時透過 _UPC & _PLD 宣告成 connectable, 與 invisiable, Microsoft 有提供下圖的流程解釋

Note: Multi Batteries on Windows XP

最近的案子有個 Dual Batteries 的需求, Battery 是設計由 EC  透過 ACPI Control method Battery 去report 給OS

基本行為是當A, B 兩顆電池同時存在時, 會先優先放電 B電池, 當B電池將到0%時, EC將會切換 放電路徑到A電池

而這個Issues 發生在當一切換電池時, OS就會發生 Crisis Battery Level Event(系統是設定 10%為Low Battery Level, 3%是Crisis Battery Level), 而此時A電池仍然為滿電力狀態. 但是確一直發生 Crisis Battery Event.

經查 ACPI 的ASL code 發現當 Battery Status change的 QEvent 發生, ASL將 Notify (\_SB.BATx, 0x80), Notify(\_SB.BATx, 0x81), Notify (\_SB.BATx, 0x80), 跟據 ACPI 4.0 spec. 指出 0x81的notify 是 Battery Information Change, 應該當Battery Replace才發生, 在XP下時, OS會因為該Event 重新抓取 Battery information 但也因此會發生 Crisis Event, 但當系統是單Battery時, 該Event並不會觸發 Crisis Battery Event. 解決之道有幾種方法, 將Battery Replace的Event重新指定另一個QEvent, 也可以在ASL中, 去儲存Battery 的Exist與否, 當狀態改變後在發出 0x81的 Notify code.

上述問題經測試在 Windows 7 上並未發生, 看來Microsoft 有改過一些OS Driver的行為模式

Note: An ACPI Debug method

在 ACPI Spec. 有定義一個Debug Object, 因此寫ASL code時可以直接使用它來Dump Debug message, 目前在Linux 的Platform 上有實作出該Object, 並將其所收到的值/字串轉向到dmesg中. 這個方法應該比在Windows 下透過 check build的 acpi.sys 方便多了!

另外當 ACPI 在初期開發階段, 很容易因為錯誤導致 Windows BSOD, Microsoft 有在KB 314830 列出一個錯誤碼的參考文件

另外一個方法是透過 acpiexec, 在 iasl 的package 可以找到該執行檔, 我在windows上試過, 不跟硬體相關的測試, 可以當做study ASL code 的 tools, 但是看起來在linux下, 功用更大 http://smackerelofopinion.blogspot.com/2010/03/debugging-acpi-using-acpiexec.html

Note: TPM with ACPI enabled OS

目前 TCG 有要求, TPM Device應該實作下列的 _DSM method 給 ACPI award 的OS使用, DTM/WHQL 會測

分別是

MOR bit: Memory Overwrite Request (MOR) bit

Ref. http://msdn.microsoft.com/en-us/library/ff567986(v=vs.85).aspx and http://msdn.microsoft.com/en-us/library/dd424551.aspx