driver: espi: it8xxx2: enable ESPI_OOB_CHANNEL

This enable eSPI out-of-band channel.

Signed-off-by: Dino Li <Dino.Li@ite.com.tw>
This commit is contained in:
Dino Li 2021-11-03 17:32:08 +08:00 committed by Anas Nashif
commit f1f0dadad3
4 changed files with 192 additions and 17 deletions

View file

@ -9,6 +9,9 @@ config ESPI_IT8XXX2
if ESPI_IT8XXX2 if ESPI_IT8XXX2
config ESPI_OOB_CHANNEL
default y
config ESPI_PERIPHERAL_8042_KBC config ESPI_PERIPHERAL_8042_KBC
default y default y

View file

@ -45,12 +45,18 @@ LOG_MODULE_REGISTER(espi, CONFIG_ESPI_LOG_LEVEL);
#define IT8XXX2_ESPI_VW_INTERRUPT_ENABLE BIT(7) #define IT8XXX2_ESPI_VW_INTERRUPT_ENABLE BIT(7)
#define IT8XXX2_ESPI_INTERRUPT_PUT_PC BIT(7) #define IT8XXX2_ESPI_INTERRUPT_PUT_PC BIT(7)
#define IT8XXX2_ESPI_UPSTREAM_ENABLE BIT(7)
#define IT8XXX2_ESPI_UPSTREAM_GO BIT(6)
#define IT8XXX2_ESPI_UPSTREAM_INTERRUPT_ENABLE BIT(5) #define IT8XXX2_ESPI_UPSTREAM_INTERRUPT_ENABLE BIT(5)
#define IT8XXX2_ESPI_UPSTREAM_CHANNEL_DISABLE BIT(2) #define IT8XXX2_ESPI_UPSTREAM_CHANNEL_DISABLE BIT(2)
#define IT8XXX2_ESPI_UPSTREAM_DONE BIT(1) #define IT8XXX2_ESPI_UPSTREAM_DONE BIT(1)
#define IT8XXX2_ESPI_UPSTREAM_BUSY BIT(0)
#define IT8XXX2_ESPI_CYCLE_TYPE_OOB 0x07
#define IT8XXX2_ESPI_PUT_OOB_STATUS BIT(7) #define IT8XXX2_ESPI_PUT_OOB_STATUS BIT(7)
#define IT8XXX2_ESPI_PUT_OOB_INTERRUPT_ENABLE BIT(7) #define IT8XXX2_ESPI_PUT_OOB_INTERRUPT_ENABLE BIT(7)
#define IT8XXX2_ESPI_PUT_OOB_LEN_MASK GENMASK(6, 0)
#define IT8XXX2_ESPI_INPUT_PAD_GATING BIT(6) #define IT8XXX2_ESPI_INPUT_PAD_GATING BIT(6)
@ -66,6 +72,9 @@ struct espi_it8xxx2_config {
struct espi_it8xxx2_data { struct espi_it8xxx2_data {
sys_slist_t callbacks; sys_slist_t callbacks;
#ifdef CONFIG_ESPI_OOB_CHANNEL
struct k_sem oob_upstream_go;
#endif
}; };
/* Driver convenience defines */ /* Driver convenience defines */
@ -687,23 +696,146 @@ static int espi_it8xxx2_write_lpc_request(const struct device *dev,
} }
#ifdef CONFIG_ESPI_OOB_CHANNEL #ifdef CONFIG_ESPI_OOB_CHANNEL
/* eSPI cycle type field */
#define ESPI_OOB_CYCLE_TYPE 0x21
#define ESPI_OOB_TAG 0x00
#define ESPI_OOB_TIMEOUT_MS 200
/* eSPI oob cycle type, tag, and length fields. */
#define ESPI_OOB_PACKET_SIZE_WITHOUT_DATA_BYTE 3
struct espi_oob_msg_packet {
uint8_t cycle_type;
uint8_t tag_len_bit_11_8;
uint8_t len_bit_7_0;
uint8_t data_byte[0];
};
static int espi_it8xxx2_send_oob(const struct device *dev, static int espi_it8xxx2_send_oob(const struct device *dev,
struct espi_oob_packet *pckt) struct espi_oob_packet *pckt)
{ {
/* TODO: implement me... */ const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev);
ARG_UNUSED(dev); struct espi_slave_regs *const slave_reg =
(struct espi_slave_regs *)config->base_espi_slave;
struct espi_queue1_regs *const queue1_reg =
(struct espi_queue1_regs *)config->base_espi_queue1;
struct espi_oob_msg_packet *oob_pckt =
(struct espi_oob_msg_packet *)pckt->buf;
uint16_t oob_msg_len;
__ASSERT(pckt->len >= ESPI_OOB_PACKET_SIZE_WITHOUT_DATA_BYTE,
"Invalid OOB packet length");
if (!(slave_reg->CH_OOB_CAPCFG3 & IT8XXX2_ESPI_OOB_READY_MASK)) {
LOG_ERR("%s: OOB channel isn't ready", __func__);
return -EIO; return -EIO;
} }
if (slave_reg->ESUCTRL0 & IT8XXX2_ESPI_UPSTREAM_BUSY) {
LOG_ERR("%s: OOB upstream busy", __func__);
return -EIO;
}
oob_msg_len = oob_pckt->len_bit_7_0 |
((oob_pckt->tag_len_bit_11_8 & 0xf) << 8);
if (pckt->len < (oob_msg_len +
ESPI_OOB_PACKET_SIZE_WITHOUT_DATA_BYTE)) {
LOG_ERR("%s: Out of tx buf %d vs %d", __func__, pckt->len,
(oob_msg_len + ESPI_OOB_PACKET_SIZE_WITHOUT_DATA_BYTE));
return -EINVAL;
}
if (oob_msg_len > ESPI_IT8XXX2_OOB_MAX_PAYLOAD_SIZE) {
LOG_ERR("%s: Out of OOB queue space", __func__);
return -EINVAL;
}
/* Set cycle type */
slave_reg->ESUCTRL1 = IT8XXX2_ESPI_CYCLE_TYPE_OOB;
/* Set tag and length[11:8] */
slave_reg->ESUCTRL2 = oob_pckt->tag_len_bit_11_8;
/* Set length [7:0] */
slave_reg->ESUCTRL3 = oob_pckt->len_bit_7_0;
/* Set data byte */
for (int i = 0; i < oob_msg_len; i++) {
queue1_reg->UPSTREAM_DATA[i] = oob_pckt->data_byte[i];
}
/* Set upstream enable */
slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_ENABLE;
/* Set upstream go */
slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_GO;
return 0;
}
static int espi_it8xxx2_receive_oob(const struct device *dev, static int espi_it8xxx2_receive_oob(const struct device *dev,
struct espi_oob_packet *pckt) struct espi_oob_packet *pckt)
{ {
/* TODO: implement me... */ const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev);
ARG_UNUSED(dev); struct espi_it8xxx2_data *const data = DRV_DATA(dev);
struct espi_slave_regs *const slave_reg =
(struct espi_slave_regs *)config->base_espi_slave;
struct espi_queue0_regs *const queue0_reg =
(struct espi_queue0_regs *)config->base_espi_queue0;
struct espi_oob_msg_packet *oob_pckt =
(struct espi_oob_msg_packet *)pckt->buf;
int ret;
uint8_t oob_len;
if (!(slave_reg->CH_OOB_CAPCFG3 & IT8XXX2_ESPI_OOB_READY_MASK)) {
LOG_ERR("%s: OOB channel isn't ready", __func__);
return -EIO; return -EIO;
} }
/* Wait until receive OOB message or timeout */
ret = k_sem_take(&data->oob_upstream_go, K_MSEC(ESPI_OOB_TIMEOUT_MS));
if (ret == -EAGAIN) {
LOG_ERR("%s: Timeout", __func__);
return -ETIMEDOUT;
}
/* Get length */
oob_len = (slave_reg->ESOCTRL4 & IT8XXX2_ESPI_PUT_OOB_LEN_MASK);
/*
* Buffer passed to driver isn't enough.
* The first three bytes of buffer are cycle type, tag, and length.
*/
if ((oob_len + ESPI_OOB_PACKET_SIZE_WITHOUT_DATA_BYTE) > pckt->len) {
LOG_ERR("%s: Out of rx buf %d vs %d", __func__,
(oob_len + ESPI_OOB_PACKET_SIZE_WITHOUT_DATA_BYTE), pckt->len);
return -EINVAL;
}
oob_pckt->cycle_type = ESPI_OOB_CYCLE_TYPE;
oob_pckt->tag_len_bit_11_8 = ESPI_OOB_TAG;
oob_pckt->len_bit_7_0 = oob_len;
/* Get data byte */
for (int i = 0; i < oob_pckt->len_bit_7_0; i++) {
oob_pckt->data_byte[i] = queue0_reg->PUT_OOB_DATA[i];
}
return 0;
}
static void espi_it8xxx2_oob_init(const struct device *dev)
{
const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev);
struct espi_it8xxx2_data *const data = DRV_DATA(dev);
struct espi_slave_regs *const slave_reg =
(struct espi_slave_regs *)config->base_espi_slave;
k_sem_init(&data->oob_upstream_go, 0, 1);
/* Upstream interrupt enable */
slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_INTERRUPT_ENABLE;
/* PUT_OOB interrupt enable */
slave_reg->ESOCTRL1 |= IT8XXX2_ESPI_PUT_OOB_INTERRUPT_ENABLE;
}
#endif #endif
/* eSPI driver registration */ /* eSPI driver registration */
@ -1052,6 +1184,7 @@ static void espi_it8xxx2_put_pc_status_isr(const struct device *dev)
slave_reg->ESPCTRL0 = IT8XXX2_ESPI_INTERRUPT_PUT_PC; slave_reg->ESPCTRL0 = IT8XXX2_ESPI_INTERRUPT_PUT_PC;
} }
#ifdef CONFIG_ESPI_OOB_CHANNEL
static void espi_it8xxx2_upstream_channel_disable_isr(const struct device *dev) static void espi_it8xxx2_upstream_channel_disable_isr(const struct device *dev)
{ {
const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev);
@ -1070,23 +1203,25 @@ static void espi_it8xxx2_upstream_done_isr(const struct device *dev)
struct espi_slave_regs *const slave_reg = struct espi_slave_regs *const slave_reg =
(struct espi_slave_regs *)config->base_espi_slave; (struct espi_slave_regs *)config->base_espi_slave;
LOG_INF("isr %s is ignored!", __func__);
/* write-1 to clear this bit */ /* write-1 to clear this bit */
slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_DONE; slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_DONE;
/* upstream disable */
slave_reg->ESUCTRL0 &= ~IT8XXX2_ESPI_UPSTREAM_ENABLE;
} }
static void espi_it8xxx2_put_oob_status_isr(const struct device *dev) static void espi_it8xxx2_put_oob_status_isr(const struct device *dev)
{ {
const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev);
struct espi_it8xxx2_data *const data = DRV_DATA(dev);
struct espi_slave_regs *const slave_reg = struct espi_slave_regs *const slave_reg =
(struct espi_slave_regs *)config->base_espi_slave; (struct espi_slave_regs *)config->base_espi_slave;
LOG_INF("isr %s is ignored!", __func__);
/* Write-1 to clear this bit for the next coming posted transaction. */ /* Write-1 to clear this bit for the next coming posted transaction. */
slave_reg->ESOCTRL0 |= IT8XXX2_ESPI_PUT_OOB_STATUS; slave_reg->ESOCTRL0 |= IT8XXX2_ESPI_PUT_OOB_STATUS;
k_sem_give(&data->oob_upstream_go);
} }
#endif
/* /*
* The ISR of espi interrupt event in array need to be matched bit order in * The ISR of espi interrupt event in array need to be matched bit order in
@ -1110,7 +1245,9 @@ static void espi_it8xxx2_isr(const struct device *dev)
(struct espi_slave_regs *)config->base_espi_slave; (struct espi_slave_regs *)config->base_espi_slave;
/* get espi interrupt events */ /* get espi interrupt events */
uint8_t espi_event = slave_reg->ESGCTRL0; uint8_t espi_event = slave_reg->ESGCTRL0;
#ifdef CONFIG_ESPI_OOB_CHANNEL
uint8_t espi_upstream = slave_reg->ESUCTRL0; uint8_t espi_upstream = slave_reg->ESUCTRL0;
#endif
/* write-1 to clear */ /* write-1 to clear */
slave_reg->ESGCTRL0 = espi_event; slave_reg->ESGCTRL0 = espi_event;
@ -1132,6 +1269,7 @@ static void espi_it8xxx2_isr(const struct device *dev)
espi_it8xxx2_put_pc_status_isr(dev); espi_it8xxx2_put_pc_status_isr(dev);
} }
#ifdef CONFIG_ESPI_OOB_CHANNEL
/* /*
* The corresponding channel of the eSPI upstream transaction is * The corresponding channel of the eSPI upstream transaction is
* disabled. * disabled.
@ -1149,6 +1287,7 @@ static void espi_it8xxx2_isr(const struct device *dev)
if (slave_reg->ESOCTRL0 & IT8XXX2_ESPI_PUT_OOB_STATUS) { if (slave_reg->ESOCTRL0 & IT8XXX2_ESPI_PUT_OOB_STATUS) {
espi_it8xxx2_put_oob_status_isr(dev); espi_it8xxx2_put_oob_status_isr(dev);
} }
#endif
} }
void espi_it8xxx2_enable_pad_ctrl(const struct device *dev, bool enable) void espi_it8xxx2_enable_pad_ctrl(const struct device *dev, bool enable)
@ -1208,8 +1347,8 @@ static struct espi_it8xxx2_data espi_it8xxx2_data_0;
static const struct espi_it8xxx2_config espi_it8xxx2_config_0 = { static const struct espi_it8xxx2_config espi_it8xxx2_config_0 = {
.base_espi_slave = DT_INST_REG_ADDR_BY_IDX(0, 0), .base_espi_slave = DT_INST_REG_ADDR_BY_IDX(0, 0),
.base_espi_vw = DT_INST_REG_ADDR_BY_IDX(0, 1), .base_espi_vw = DT_INST_REG_ADDR_BY_IDX(0, 1),
.base_espi_queue1 = DT_INST_REG_ADDR_BY_IDX(0, 2), .base_espi_queue0 = DT_INST_REG_ADDR_BY_IDX(0, 2),
.base_espi_queue0 = DT_INST_REG_ADDR_BY_IDX(0, 3), .base_espi_queue1 = DT_INST_REG_ADDR_BY_IDX(0, 3),
.base_ec2i = DT_INST_REG_ADDR_BY_IDX(0, 4), .base_ec2i = DT_INST_REG_ADDR_BY_IDX(0, 4),
.base_kbc = DT_INST_REG_ADDR_BY_IDX(0, 5), .base_kbc = DT_INST_REG_ADDR_BY_IDX(0, 5),
.base_pmc = DT_INST_REG_ADDR_BY_IDX(0, 6), .base_pmc = DT_INST_REG_ADDR_BY_IDX(0, 6),
@ -1259,11 +1398,9 @@ static int espi_it8xxx2_init(const struct device *dev)
DEVICE_DT_INST_GET(0), 0); DEVICE_DT_INST_GET(0), 0);
irq_enable(IT8XXX2_ESPI_VW_IRQ); irq_enable(IT8XXX2_ESPI_VW_IRQ);
/* Upstream interrupt enable */ #ifdef CONFIG_ESPI_OOB_CHANNEL
slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_INTERRUPT_ENABLE; espi_it8xxx2_oob_init(dev);
#endif
/* PUT_OOB interrupt enable */
slave_reg->ESOCTRL1 |= IT8XXX2_ESPI_PUT_OOB_INTERRUPT_ENABLE;
/* Enable espi interrupt */ /* Enable espi interrupt */
slave_reg->ESGCTRL1 |= IT8XXX2_ESPI_INTERRUPT_ENABLE; slave_reg->ESGCTRL1 |= IT8XXX2_ESPI_INTERRUPT_ENABLE;

View file

@ -55,6 +55,15 @@ IT8XXX2_REG_OFFSET_CHECK(espi_vw_regs, VW_INDEX, 0x00);
IT8XXX2_REG_OFFSET_CHECK(espi_vw_regs, VWCTRL0, 0x90); IT8XXX2_REG_OFFSET_CHECK(espi_vw_regs, VWCTRL0, 0x90);
IT8XXX2_REG_OFFSET_CHECK(espi_vw_regs, VWCTRL1, 0x91); IT8XXX2_REG_OFFSET_CHECK(espi_vw_regs, VWCTRL1, 0x91);
/* eSPI Queue 0 registers structure check */
IT8XXX2_REG_SIZE_CHECK(espi_queue0_regs, 0xd0);
IT8XXX2_REG_OFFSET_CHECK(espi_queue0_regs, PUT_OOB_DATA, 0x80);
/* eSPI Queue 1 registers structure check */
IT8XXX2_REG_SIZE_CHECK(espi_queue1_regs, 0xc0);
IT8XXX2_REG_OFFSET_CHECK(espi_queue1_regs, UPSTREAM_DATA, 0x00);
IT8XXX2_REG_OFFSET_CHECK(espi_queue1_regs, PUT_FLASH_NP_DATA, 0x80);
/* GCTRL register structure check */ /* GCTRL register structure check */
IT8XXX2_REG_SIZE_CHECK(gctrl_it8xxx2_regs, 0x88); IT8XXX2_REG_SIZE_CHECK(gctrl_it8xxx2_regs, 0x88);
IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_RSTS, 0x06); IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_RSTS, 0x06);

View file

@ -2291,6 +2291,32 @@ struct espi_vw_regs {
/* 0x98-0x99: Reserved3 */ /* 0x98-0x99: Reserved3 */
volatile uint8_t reserved3[2]; volatile uint8_t reserved3[2];
}; };
#define ESPI_IT8XXX2_OOB_MAX_PAYLOAD_SIZE 80
/*
* eSPI Queue 0 registers
*/
struct espi_queue0_regs {
/* 0x00-0x3f: PUT_PC Data Byte 0-63 */
volatile uint8_t PUT_PC_DATA[0x40];
/* 0x40-0x7f: Reserved1 */
volatile uint8_t reserved1[0x40];
/* 0x80-0xcf: PUT_OOB Data Byte 0-79 */
volatile uint8_t PUT_OOB_DATA[ESPI_IT8XXX2_OOB_MAX_PAYLOAD_SIZE];
};
/*
* eSPI Queue 1 registers
*/
struct espi_queue1_regs {
/* 0x00-0x4f: Upstream Data Byte 0-79 */
volatile uint8_t UPSTREAM_DATA[ESPI_IT8XXX2_OOB_MAX_PAYLOAD_SIZE];
/* 0x50-0x7f: Reserved1 */
volatile uint8_t reserved1[0x30];
/* 0x80-0xbf: PUT_FLASH_NP Data Byte 0-63 */
volatile uint8_t PUT_FLASH_NP_DATA[0x40];
};
#endif /* !__ASSEMBLER__ */ #endif /* !__ASSEMBLER__ */
#endif /* CHIP_CHIPREGS_H */ #endif /* CHIP_CHIPREGS_H */