62/66 端口介绍
HOST可以通过62/66 IO端口或者MMIO访问EC共享的RAM,62/66端口不像CMOS端口可以直接读写,在读写之前还要判断端口数据是否准备好了以及端口是否为空。
EC端口寄存器
读66端口,相当于读EC的状态,写66端口相当于给EC写命令,数据端口为62端口
状态寄存器
状态寄存器大小为一个字节,BIT0和BIT1可以用于HOST判断EC端口是否可写,或者是否有数据可以读取。而BIT3可用于EC端判断HOST下发的是数据还是命令
EC命令
这些命令是HOST端下发给EC的,0x80命令代表HOST要读EC RAM,0x81命令代表HOST要写EC RAM,0x82和0x83则表示是否要开启快速访问。0x84则表示HOST之前收到了EC的中断通知,要读取Q event。
读写EC RAM实例
1.判断端口状态函数
#define EC_TIME_OUT 10000
#define EC_S_IBF 0x02 // Input buffer is full/empty
#define EC_S_OBF 0x01 // Output buffer is full/empty
#define STATE_SUCCESS 0x00
#define STATE_ERROR 0x01
#define EC_D_PORT 0x62
#define EC_C_PORT 0x66
#define EC_C_READ_MEM 0x80 // Read the EC memory
#define EC_C_WRITE_MEM 0x81 // Write the EC memory
uint8_t WaitECIbe (
uint8_t CommandState
)
{
uint8_t ECCmdState = 0;
uint8_t Index;
for (Index = 0; Index < EC_TIME_OUT; Index++) {
ECCmdState = (uint8_t)ioread8 (CommandState);
if (!(ECCmdState & EC_S_IBF)) {
return STATE_SUCCESS;
} else{
usleep(15);
}
}
return STATE_ERROR;
}
uint8_t WaitECObf (
uint8_t CommandState
)
{
uint8_t ECCmdState = 0;
uint8_t Index;
for (Index = 0; Index < EC_TIME_OUT; Index++) {
ECCmdState = (uint8_t)ioread8 (CommandState);
if (ECCmdState & EC_S_OBF) {
return STATE_SUCCESS;
} else{
usleep(15);
}
}
return STATE_ERROR;
}
WaitECIbe 用于判断端口是否为空,WaitECObf 用于判断是否准备好数据。
2.发送命令以及读写数据
void SendDataToEc (
uint8_t Port,
uint8_t Data
)
{
WaitECIbe (Port); // Wait Input Buffer Empty
iowrite8 (Port - 4, Data);
WaitECIbe (Port); // Wait Input Buffer Empty
}
void SendCmdToEc (
uint8_t Port,
uint8_t Cmd
)
{
WaitECIbe (Port); // Wait Input Buffer Empty
iowrite8 (Port, Cmd);
WaitECIbe (Port); // Wait Input Buffer Empty
}
uint8_t GetDataFromEc (
uint8_t Port
)
{
uint8_t Data;
WaitECIbe (Port); // Wait Input Buffer Empty
WaitECObf (Port); // Wait Output Buffer Full
Data = ioread8 (Port - 4);
return Data;
}
以上三个函数分别用于发送数据和命令以及读取数据。有了上面三个函数之后就可以操作EC了。
3.读写EC函数
void ECWrite(
uint8_t Index,
uint8_t Value
)
{
//
// Write Command
//
SendCmdToEc (EC_C_PORT, EC_C_WRITE_MEM);
//
// send ECRAM offset to DATA port
//
SendDataToEc (EC_C_PORT, Index);
//
// Write DATA to EC ram
//
SendDataToEc (EC_C_PORT, Value);
}
首先发送0x81命令给EC告诉EC要写EC RAM,然后发送要写的index,最后把数据写入。
而读函数的话则需要把命令换为0x80。
uint8_t ECRead(
uint8_t Index
)
{
SendCmdToEc (EC_C_PORT, EC_C_READ_MEM);
//
// send ECRAM offset to DATA port
//
SendDataToEc (EC_C_PORT, Index);
//
// get DATA from EC
//
return GetDataFromEc (EC_C_PORT);
}
4.在BIOS下IoLib里面有IoRead8和IoWrite8函数调用,而在linux下可以实现如下
#include <stdint.h>
#include <stdbool.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
static int fd;
bool port_dev_init(void)
{
fd = open("/dev/port", O_RDWR);
if (fd < 0) {
return false;
}
return true;
}
void port_dev_exit(void)
{
close(fd);
}
uint8_t ioread8(uint16_t port)
{
uint8_t buf[2] = { 0 };
lseek(fd, port, SEEK_SET);
read(fd, buf, 1);
return buf[0];
}
void iowrite8(uint16_t port, uint8_t data)
{
uint8_t buf[2] = { 0 };
lseek(fd, port, SEEK_SET);
buf[0] = data;
write(fd, buf, 1);
}