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的宣告。

 

 


  • 15
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值