LPC(Low Pin Count)接口时Intel推出的一种低IO数目的外设接口,用于连接SuperIO、Flash等LPC设备
操作说明:
使用LPC功能前,需要先配置相关PAD服用寄存器,将对应PAD配置到对应LPC功能上,才可使用LPC功能:
1、判断想要访问设备的接口访问类型,然后通过APB接口地址的设备类型寄存器发送对应的IO、FIRMWARE Memory、Memory、DMA请求。
2、通过nu_serirq_config[31]判断是4字节读取还是单字节读取。
首先获取LPC的基地址,如基地址为0x000_20000000
再去查看寄存器,以下面的代码为例子:
MmioWrite32(0x27ffffcc, 1);
MmioWrite32(0x27ffffe8, 0x80000000);
MmioWrite32(0x27ffffd8, 0);
MmioWrite32(0x27ffffd4, 0);
第一个偏移地址写1,具体可以参考LPC协议文档
主要是BIT3-BIT0:
000为IO read,001为IO write,010为memory read......
第二个偏移地址写值0x80000000,也就是上文说的nu_serirq_config[31],描述如下:
配置寄存器(bit31:针对读数据每次读4 bytes数据使能标志(1’b1:读1byte); bit1~0:起始周期配置(2’b11:8;2’b10:6;否则4,默认4 clk), bit2:串行中断模式配置默认连续模式 默认为连续模式), bit3~4:支持的串行中断设备数量(2‘b01 代表32 否则16默认16)
第三个中断屏蔽寄存器,第四个为配置启动周期寄存器
写完上面的,咱们就可以通过LPC进行IO读写操作了,以EC与BIOS通信为例
EC提供256字节的可被系统读写的RAM空间,EC的资源在该RAM空间映射,通过访问对应偏移(0x00~0xFF),即可操作对应的资源。了解EC的特别是ITE的,都清楚62、66端口,如果BIOS想要获取EC寄存器中的值,那么需要在基地址的基础上再加上62、66
比如:
#define LPC_MEM_BASE 0x20000000
#define EC_COMMAND_PORT 0x66 | LPC_MEM_BASE
#define EC_DATA_PORT 0x62 | LPC_MEM_BASE
后续EC读写代码如下:
#include <Base.h>
#include <Library/BaseLib.h>
#include <Library/IoLib.h>
#include <Library/EcLib.h>
#include <Library/DebugLib.h>
#include <Library/TimerLib.h>
EFI_STATUS
EcIbFree ()
{
EFI_STATUS Status = EFI_SUCCESS;
UINTN Count = 10000;
UINT8 Data;
do {
Data = MmioRead8(EC_COMMAND_PORT);
if ((Data & EC_IBF) == 0) {
break;
}
MicroSecondDelay (1000);
Count --;
} while (Count);
if (Count == 0) {
Status = EFI_TIMEOUT;
}
return Status;
}
EFI_STATUS
EcObFull()
{
EFI_STATUS Status = EFI_SUCCESS;
UINTN Count = 10000;
UINT8 Data;
do {
Data = MmioRead8(EC_COMMAND_PORT);
if (Data & EC_OBF) {
break;
}
MicroSecondDelay (1000);
Count --;
} while (Count);
if (Count == 0) {
Status = EFI_TIMEOUT;
}
return Status;
}
EFI_STATUS
EcWriteCmd (
UINT8 cmd
)
{
while((MmioRead8(EC_COMMAND_PORT)) & EC_OBF) {
MmioRead8(EC_DATA_PORT);
}
EcIbFree();
MmioWrite8(EC_COMMAND_PORT, cmd);
EcIbFree();
return EFI_SUCCESS;
}
EFI_STATUS
EcWriteData (
UINT8 data
)
{
EcIbFree();
MmioWrite8(EC_DATA_PORT, data);
EcIbFree();
return EFI_SUCCESS;
}
EFI_STATUS
EcReadData (
UINT8 *pData
)
{
if (EFI_ERROR(EcObFull()))
return EFI_DEVICE_ERROR;
*pData=MmioRead8(EC_DATA_PORT);
return EFI_SUCCESS;
}
EFI_STATUS
EcReadMem (
UINT8 Index,
UINT8 *Data
)
{
UINT8 cmd = 0x80;
EcWriteCmd (cmd);
EcWriteData(Index);
EcReadData(Data);
return EFI_SUCCESS;
}
EFI_STATUS
EcWriteMem (
UINT8 Index,
UINT8 Data
)
{
UINT8 cmd = 0x81;
EcWriteCmd (cmd);
EcWriteData(Index);
EcWriteData(Data);
return EFI_SUCCESS;
}