Bios工程師手邊事—SBIOS添加EC功能

前言:敬畏主就是智慧,遠離惡便是聰明(還是守着本心吧)。

在筆記本平臺中,我們經常用到EC芯片。從BIOS角度來看,EC在平臺中的地位和SuperIO,BMC沒有什麼不同:都是掛在LPC下面;所用IO端口都要解碼至LPCbridge上;都要爲ACPI OS提供ASL Device,以供其驅動裝載和調用。

    本文針對EC,談一下在SBIOS中如何添加其功能模塊,使得EC功能可以正常使用。如果知道EC怎麼訪問,那麼SuperIO和BMC也就沒什麼特殊的了。

 

1. IO地址解碼

SBIOS如果想訪問EC,就需要將HOST端的IO地址和EC端的寄存器對應起來。只有這樣,HOST端纔可以和EC通信。想做到這些,必須要做兩件事。使能邏輯設備和解碼相應IO地址至LPC bridge。

 

1.1 使能邏輯設備

1.1.1 BaseAddress

首先要搞懂EC所使用的Base Address,因爲想要訪問邏輯設備,都是通過Base Address來進行的。這是一對IO端口,我們經常叫做Index IO,Data IO。對於以前的EC芯片,Base Address都是通過HW進行strap的,現在的EC芯片大多是sw進行strap的,直接在EC裏面將想使用的Base Address填入特定的寄存器即可。Base Address一般是2E/2F,4E/4F,164E/164F其中一對,當然我們也可以自定義。只要在EC中填寫相應的值,然後在LPC bridge中進行解碼即可。

1.1.2 邏輯設備

    從整個平臺來講,EC屬於LPC下的一個物理設備。但其功能上,可以劃分很多模塊,如Keyboard,Mouse,PM1,PM2,PM3,UART,CIR,SHM等,我想這就是稱其爲邏輯設備的原因吧。我們可以對單獨的某個邏輯設備進行使能和禁止,因爲每一個邏輯設備都對應一個邏輯設備號。我們訪問邏輯設備時,首先要將邏輯設備號寫入PNPCFG register的offset 07處,這樣就選擇了該邏輯設備,在改寫其0x30~0xFF處的值,就等於對該邏輯設備進行配置了。

 

那麼我們來看一下下面一段代碼:

IoWrite8(0x4E,0x07);

IoWrite8(0x4F,0x05);

IoWrite8(0x4E,0x30);

IoWrite8(0x4F,0x01);

從代碼中可看到,BaseAddress是0x4E/0x4F。前兩行代碼,是選擇了一個邏輯設備號爲5的設備。後兩行是使能該邏輯設備。有過這方面經驗的工程師一看到5,就知道這個是使能鍵盤了。其所使用的IO地址默認爲60/64,分別在PNPCFGregister的offset 60,61,62,63處填寫。

 

1.2 解碼至LPC

    真要做到地址解碼,除了EC端還不行,那只是EC端的一廂情願。如果要解碼60/64,LPC Bridge首先要承認這個IO地址屬於它的,也就是要把60/64解碼到LPC橋上。那麼X86 CPU在BUS上訪問60/64時,LPC纔會將相應數據抓過來。對於INTEL的橋片來說,解碼60/64很簡單,只需要在LPC config space裏使能相應bit位即可。

對於一些不常用的IO端口,如果EC想據爲已有,怎麼辦呢?對於INTEL橋片來講,其lpc bridge上有專門的四個decode range寄存器,我們可以用它們來解碼相應的IO。然後在EC的邏輯設備中選擇一個,在60/61/62/63處填寫即可。

 

這些做完之後,DXE階段的驅動所需要的資源就準備好了。Keyboard,Mouse,UART的驅動就可以正常地使用了。

 

2. 62/66端口

如果有人問我,對於BIOS工程師來講,EC區別於SUPERIO之處在哪裏?我會回答,62/66端口。因爲有SUPER IO的平臺,ACPI OS下不會有EC的驅動,有EC的平臺,ACPI OS會加載一個EC驅動。因爲EC的驅動所需要的重要資源之一,就是62/66端口,這是EC所獨有的。

系統如何訪問62/66端口,都在ACPI SPEC中第12章節寫明。具體看下圖:

 

圖1. EC Command



    這上面的五個Command Byte Encoding,在ACPI OS下都是以中斷的方式進行的。80命令讀取EC Space的值;81命令可以改寫EC space的值;82/83是讓EC進入一種Burst模式,在這種模式下,OS以Polling方式和EC交互,雖然數據是以Polling方式傳輸,但82/83命令是以中斷的方式來握手的,很多EC工程師不注意,造成系統經常啓動時死機。其實不是死機,只是ACPI OS在等待中斷而已。84命令是讓EC驅動讀取Qevent值。

    在BIOS啓動過程中,我們經常要讀取EC版本和其相關信息,就要通過80命令。但是由於沒有註冊SCI中斷,所以我們只能通過POLLING的方式來和EC進行交互,說白了就是以不斷檢查狀態寄存器的方式來詢問EC代碼是否執行完。但我們也可以不操作EC Space,自定義其它的command,如:SBIOS工程師和ECBIOS工程師約定往0x66寫0x50,然後讀0x62爲版本號中的一位,我們可以按如下方式讀寫:

    IoRead8(0x62);

    CheckIBF();

    IoWrite8(0x66,0x50);

    CheckOBF();

    Result := IoRead8(0x62);

第一行代碼看似無關緊要,但最好帶上,以免出現奇奇怪怪的BUG。我們的Linux內核經常出現調節亮度,按三次鍵盤亮度只調節一格的問題,我只在EC driver中加了上面一行代碼就解決問題了。針對OBF的問題,靠EC是完成不了,只能依靠HOST端了。

 

3. ASL宣告Device

有了EC,就要宣告EC設備,將相應的IO資源和SCI中斷資源報上去。只有這樣,EC driver才能正常加載。我們來看一下,ACPI SPEC怎麼宣告EC device的。

 

Device(\_EC0) {
// PnP ID
Name(_HID, EISAID(PNP0C09))
// Returns the “Current Resources” of EC
Name(_CRS, Buffer(){0x4B, 0x62, 0, 1, 0x4B,
0x66, 0, 1, 0x79, 0})
// Define that the EC SCI is bit 0 of the GP_STS register
Name(_GPE, 0) // embedded controller is wired to bit 0 of GPE
OperationRegion(\EC0, EmbeddedControl, 0, 0xFF)
Field(\EC0, AnyAcc, Lock, Preserve) {
// Field definitions
}
Method(Q00){..}
Method(QFF){..}
}

 

這是最小化的代碼,ACPI1.0 SPEC的,所以和現在的SPEC有些出入。但是作爲宣告EC Device的模板,還是可以的。

宣告EC Device,首先要有_HID,有了它,EC驅動才知道這是個EC Device。

_CRS和_GPE,有了它EC驅動就可以知道所用的IO端口和SCI中斷源。EC驅動首先工獲取它們,然後才能註冊中斷,才能確認操作EC所使用的command_addr和data_addr。

因爲我們還要操作EC SPACE,所以要有EmbededControl型的OperationRegion。如果說其它區域是代碼區域,那麼這個OperationRegion就是數據區域了。EC driver和EC進行交互所需要的數據都要在這裏聲明。

爲了觸發動作,還需要有一系列的QEvent。根據Qevent所要求執行的具體動作,在Qevent和Method裏面添加相應的代碼,一般來講,都是直接通知驅動執行相應的功能。

除了這些,EC往往還要支持電池,指示LID,AC狀態。所以還要添加幾個Device的宣告。

 

 


發佈了28 篇原創文章 · 獲贊 21 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章