driver: espi: it8xxx2: enable CONFIG_ESPI_FLASH_CHANNEL

This enable eSPI flash channel.

Signed-off-by: Dino Li <Dino.Li@ite.com.tw>
This commit is contained in:
Dino Li 2021-11-19 15:17:33 +08:00 committed by Christopher Friedt
parent 15a9be674a
commit 03fea69272
2 changed files with 283 additions and 18 deletions

View file

@ -21,6 +21,9 @@ config ESPI_PERIPHERAL_HOST_IO
config ESPI_PERIPHERAL_DEBUG_PORT_80
default y
config ESPI_FLASH_CHANNEL
default y
config ESPI_IT8XXX2_PNPCFG_DEVICE_KBC_MOUSE
bool "ITE IT8XXX2 KBC mouse device"
help

View file

@ -60,6 +60,10 @@ LOG_MODULE_REGISTER(espi, CONFIG_ESPI_LOG_LEVEL);
#define IT8XXX2_ESPI_INPUT_PAD_GATING BIT(6)
#define IT8XXX2_ESPI_FLASH_MAX_PAYLOAD_SIZE 64
#define IT8XXX2_ESPI_PUT_FLASH_TAG_MASK GENMASK(7, 4)
#define IT8XXX2_ESPI_PUT_FLASH_LEN_MASK GENMASK(6, 0)
struct espi_it8xxx2_config {
uintptr_t base_espi_slave;
uintptr_t base_espi_vw;
@ -75,6 +79,13 @@ struct espi_it8xxx2_data {
#ifdef CONFIG_ESPI_OOB_CHANNEL
struct k_sem oob_upstream_go;
#endif
#ifdef CONFIG_ESPI_FLASH_CHANNEL
struct k_sem flash_upstream_go;
uint8_t put_flash_cycle_type;
uint8_t put_flash_tag;
uint8_t put_flash_len;
uint8_t flash_buf[IT8XXX2_ESPI_FLASH_MAX_PAYLOAD_SIZE];
#endif
};
struct vw_channel_t {
@ -834,6 +845,236 @@ static void espi_it8xxx2_oob_init(const struct device *dev)
}
#endif
#ifdef CONFIG_ESPI_FLASH_CHANNEL
#define ESPI_FLASH_TAG 0x01
#define ESPI_FLASH_READ_TIMEOUT_MS 200
#define ESPI_FLASH_WRITE_TIMEOUT_MS 500
#define ESPI_FLASH_ERASE_TIMEOUT_MS 1000
/* Successful completion without data */
#define ESPI_IT8XXX2_PUT_FLASH_C_SCWOD 0
/* Successful completion with data */
#define ESPI_IT8XXX2_PUT_FLASH_C_SCWD 4
enum espi_flash_cycle_type {
IT8XXX2_ESPI_CYCLE_TYPE_FLASH_READ = 0x08,
IT8XXX2_ESPI_CYCLE_TYPE_FLASH_WRITE = 0x09,
IT8XXX2_ESPI_CYCLE_TYPE_FLASH_ERASE = 0x0A,
};
static int espi_it8xxx2_flash_trans(const struct device *dev,
struct espi_flash_packet *pckt,
enum espi_flash_cycle_type tran)
{
const struct espi_it8xxx2_config *const config = dev->config;
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;
if (!(slave_reg->CH_FLASH_CAPCFG3 & IT8XXX2_ESPI_FC_READY_MASK)) {
LOG_ERR("%s: Flash channel isn't ready (tran:%d)",
__func__, tran);
return -EIO;
}
if (slave_reg->ESUCTRL0 & IT8XXX2_ESPI_UPSTREAM_BUSY) {
LOG_ERR("%s: Upstream busy (tran:%d)", __func__, tran);
return -EIO;
}
if (pckt->len > IT8XXX2_ESPI_FLASH_MAX_PAYLOAD_SIZE) {
LOG_ERR("%s: Invalid size request (tran:%d)", __func__, tran);
return -EINVAL;
}
/* Set cycle type */
slave_reg->ESUCTRL1 = tran;
/* Set tag and length[11:8] */
slave_reg->ESUCTRL2 = (ESPI_FLASH_TAG << 4);
/*
* Set length [7:0]
* Note: for erasing, the least significant 3 bit of the length field
* specifies the size of the block to be erased:
* 001b: 4 Kbytes
* 010b: 64Kbytes
* 100b: 128 Kbytes
* 101b: 256 Kbytes
*/
slave_reg->ESUCTRL3 = pckt->len;
/* Set flash address */
queue1_reg->UPSTREAM_DATA[0] = (pckt->flash_addr >> 24) & 0xff;
queue1_reg->UPSTREAM_DATA[1] = (pckt->flash_addr >> 16) & 0xff;
queue1_reg->UPSTREAM_DATA[2] = (pckt->flash_addr >> 8) & 0xff;
queue1_reg->UPSTREAM_DATA[3] = pckt->flash_addr & 0xff;
return 0;
}
static int espi_it8xxx2_flash_read(const struct device *dev,
struct espi_flash_packet *pckt)
{
const struct espi_it8xxx2_config *const config = dev->config;
struct espi_it8xxx2_data *const data = dev->data;
struct espi_slave_regs *const slave_reg =
(struct espi_slave_regs *)config->base_espi_slave;
int ret;
ret = espi_it8xxx2_flash_trans(dev, pckt,
IT8XXX2_ESPI_CYCLE_TYPE_FLASH_READ);
if (ret) {
return ret;
}
/* Set upstream enable */
slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_ENABLE;
/* Set upstream go */
slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_GO;
/* Wait until upstream done or timeout */
ret = k_sem_take(&data->flash_upstream_go,
K_MSEC(ESPI_FLASH_READ_TIMEOUT_MS));
if (ret == -EAGAIN) {
LOG_ERR("%s: Timeout", __func__);
return -ETIMEDOUT;
}
if (data->put_flash_cycle_type != ESPI_IT8XXX2_PUT_FLASH_C_SCWD) {
LOG_ERR("%s: Unsuccessful completion", __func__);
return -EIO;
}
memcpy(pckt->buf, data->flash_buf, pckt->len);
LOG_INF("%s: read (%d) bytes from flash over espi", __func__,
data->put_flash_len);
return 0;
}
static int espi_it8xxx2_flash_write(const struct device *dev,
struct espi_flash_packet *pckt)
{
const struct espi_it8xxx2_config *const config = dev->config;
struct espi_it8xxx2_data *const data = dev->data;
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;
int ret;
ret = espi_it8xxx2_flash_trans(dev, pckt,
IT8XXX2_ESPI_CYCLE_TYPE_FLASH_WRITE);
if (ret) {
return ret;
}
/* Set data byte */
for (int i = 0; i < pckt->len; i++) {
queue1_reg->UPSTREAM_DATA[4 + i] = pckt->buf[i];
}
/* Set upstream enable */
slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_ENABLE;
/* Set upstream go */
slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_GO;
/* Wait until upstream done or timeout */
ret = k_sem_take(&data->flash_upstream_go,
K_MSEC(ESPI_FLASH_WRITE_TIMEOUT_MS));
if (ret == -EAGAIN) {
LOG_ERR("%s: Timeout", __func__);
return -ETIMEDOUT;
}
if (data->put_flash_cycle_type != ESPI_IT8XXX2_PUT_FLASH_C_SCWOD) {
LOG_ERR("%s: Unsuccessful completion", __func__);
return -EIO;
}
return 0;
}
static int espi_it8xxx2_flash_erase(const struct device *dev,
struct espi_flash_packet *pckt)
{
const struct espi_it8xxx2_config *const config = dev->config;
struct espi_it8xxx2_data *const data = dev->data;
struct espi_slave_regs *const slave_reg =
(struct espi_slave_regs *)config->base_espi_slave;
int ret;
ret = espi_it8xxx2_flash_trans(dev, pckt,
IT8XXX2_ESPI_CYCLE_TYPE_FLASH_ERASE);
if (ret) {
return ret;
}
/* Set upstream enable */
slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_ENABLE;
/* Set upstream go */
slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_GO;
/* Wait until upstream done or timeout */
ret = k_sem_take(&data->flash_upstream_go,
K_MSEC(ESPI_FLASH_ERASE_TIMEOUT_MS));
if (ret == -EAGAIN) {
LOG_ERR("%s: Timeout", __func__);
return -ETIMEDOUT;
}
if (data->put_flash_cycle_type != ESPI_IT8XXX2_PUT_FLASH_C_SCWOD) {
LOG_ERR("%s: Unsuccessful completion", __func__);
return -EIO;
}
return 0;
}
static void espi_it8xxx2_flash_upstream_done_isr(const struct device *dev)
{
const struct espi_it8xxx2_config *const config = dev->config;
struct espi_it8xxx2_data *const data = dev->data;
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;
data->put_flash_cycle_type = slave_reg->ESUCTRL6;
data->put_flash_tag = slave_reg->ESUCTRL7 &
IT8XXX2_ESPI_PUT_FLASH_TAG_MASK;
data->put_flash_len = slave_reg->ESUCTRL8 &
IT8XXX2_ESPI_PUT_FLASH_LEN_MASK;
if (slave_reg->ESUCTRL1 == IT8XXX2_ESPI_CYCLE_TYPE_FLASH_READ) {
if (data->put_flash_len > IT8XXX2_ESPI_FLASH_MAX_PAYLOAD_SIZE) {
LOG_ERR("%s: Invalid size (%d)", __func__,
data->put_flash_len);
} else {
for (int i = 0; i < data->put_flash_len; i++) {
data->flash_buf[i] =
queue1_reg->UPSTREAM_DATA[i];
}
}
}
k_sem_give(&data->flash_upstream_go);
}
static void espi_it8xxx2_flash_init(const struct device *dev)
{
const struct espi_it8xxx2_config *const config = dev->config;
struct espi_it8xxx2_data *const data = dev->data;
struct espi_slave_regs *const slave_reg =
(struct espi_slave_regs *)config->base_espi_slave;
k_sem_init(&data->flash_upstream_go, 0, 1);
/* Upstream interrupt enable */
slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_INTERRUPT_ENABLE;
}
#endif /* CONFIG_ESPI_FLASH_CHANNEL */
/* eSPI driver registration */
static int espi_it8xxx2_init(const struct device *dev);
@ -849,6 +1090,11 @@ static const struct espi_driver_api espi_it8xxx2_driver_api = {
.send_oob = espi_it8xxx2_send_oob,
.receive_oob = espi_it8xxx2_receive_oob,
#endif
#ifdef CONFIG_ESPI_FLASH_CHANNEL
.flash_read = espi_it8xxx2_flash_read,
.flash_write = espi_it8xxx2_flash_write,
.flash_erase = espi_it8xxx2_flash_erase,
#endif
};
static void espi_it8xxx2_vw_notify_system_state(const struct device *dev,
@ -1193,18 +1439,6 @@ static void espi_it8xxx2_upstream_channel_disable_isr(const struct device *dev)
slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_CHANNEL_DISABLE;
}
static void espi_it8xxx2_upstream_done_isr(const struct device *dev)
{
const struct espi_it8xxx2_config *const config = dev->config;
struct espi_slave_regs *const slave_reg =
(struct espi_slave_regs *)config->base_espi_slave;
/* write-1 to clear this bit */
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)
{
const struct espi_it8xxx2_config *const config = dev->config;
@ -1219,6 +1453,27 @@ static void espi_it8xxx2_put_oob_status_isr(const struct device *dev)
}
#endif
#if defined(CONFIG_ESPI_OOB_CHANNEL) || defined(CONFIG_ESPI_FLASH_CHANNEL)
static void espi_it8xxx2_upstream_done_isr(const struct device *dev)
{
const struct espi_it8xxx2_config *const config = dev->config;
struct espi_slave_regs *const slave_reg =
(struct espi_slave_regs *)config->base_espi_slave;
#ifdef CONFIG_ESPI_FLASH_CHANNEL
/* cycle type is flash read, write, or erase */
if (slave_reg->ESUCTRL1 != IT8XXX2_ESPI_CYCLE_TYPE_OOB) {
espi_it8xxx2_flash_upstream_done_isr(dev);
}
#endif
/* write-1 to clear this bit */
slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_DONE;
/* upstream disable */
slave_reg->ESUCTRL0 &= ~IT8XXX2_ESPI_UPSTREAM_ENABLE;
}
#endif
/*
* The ISR of espi interrupt event in array need to be matched bit order in
* IT8XXX2 ESPI ESGCTRL0 register.
@ -1241,7 +1496,7 @@ static void espi_it8xxx2_isr(const struct device *dev)
(struct espi_slave_regs *)config->base_espi_slave;
/* get espi interrupt events */
uint8_t espi_event = slave_reg->ESGCTRL0;
#ifdef CONFIG_ESPI_OOB_CHANNEL
#if defined(CONFIG_ESPI_OOB_CHANNEL) || defined(CONFIG_ESPI_FLASH_CHANNEL)
uint8_t espi_upstream = slave_reg->ESUCTRL0;
#endif
@ -1274,16 +1529,19 @@ static void espi_it8xxx2_isr(const struct device *dev)
espi_it8xxx2_upstream_channel_disable_isr(dev);
}
/* The eSPI upstream transaction is done. */
if (espi_upstream & IT8XXX2_ESPI_UPSTREAM_DONE) {
espi_it8xxx2_upstream_done_isr(dev);
}
/* The eSPI slave has received a PUT_OOB message. */
if (slave_reg->ESOCTRL0 & IT8XXX2_ESPI_PUT_OOB_STATUS) {
espi_it8xxx2_put_oob_status_isr(dev);
}
#endif
/* eSPI oob and flash channels use the same interrupt of upstream. */
#if defined(CONFIG_ESPI_OOB_CHANNEL) || defined(CONFIG_ESPI_FLASH_CHANNEL)
/* The eSPI upstream transaction is done. */
if (espi_upstream & IT8XXX2_ESPI_UPSTREAM_DONE) {
espi_it8xxx2_upstream_done_isr(dev);
}
#endif
}
void espi_it8xxx2_enable_pad_ctrl(const struct device *dev, bool enable)
@ -1398,6 +1656,10 @@ static int espi_it8xxx2_init(const struct device *dev)
espi_it8xxx2_oob_init(dev);
#endif
#ifdef CONFIG_ESPI_FLASH_CHANNEL
espi_it8xxx2_flash_init(dev);
#endif
/* Enable espi interrupt */
slave_reg->ESGCTRL1 |= IT8XXX2_ESPI_INTERRUPT_ENABLE;
IRQ_CONNECT(IT8XXX2_ESPI_IRQ, 0, espi_it8xxx2_isr,