drivers: espi: npcx: workaround Global Reset issue

Apply the workaround for the issue "eSPI global reset" in the
NPCX49nF_Errata

Signed-off-by: Tom Chang <CHChang19@nuvoton.com>
This commit is contained in:
Tom Chang 2024-03-05 11:15:37 +08:00 committed by Fabio Baltieri
parent d921659d6a
commit 0e4b5de6ca
2 changed files with 49 additions and 0 deletions

View file

@ -118,4 +118,10 @@ config ESPI_NPCX_SUPP_VW_GPIO
help
Selected if NPCX series supports virtual wire GPIOs in eSPI module.
config ESPI_NPCX_CAF_GLOBAL_RESET_WORKAROUND
bool
default y if SOC_SERIES_NPCX4 && ESPI_FLASH_CHANNEL
help
Workaround the issue "Global Reset" in the npcx4 SoC errata.
endif #ESPI_NPCX

View file

@ -46,6 +46,10 @@ struct espi_npcx_data {
#if defined(CONFIG_ESPI_FLASH_CHANNEL)
struct k_sem flash_rx_lock;
#endif
#ifdef CONFIG_ESPI_NPCX_CAF_GLOBAL_RESET_WORKAROUND
/* tell the interrupt handler that it is a fake request */
bool fake_req_flag;
#endif
};
/* Driver convenience defines */
@ -190,6 +194,13 @@ static int espi_npcx_send_vwire(const struct device *dev,
enum espi_vwire_signal signal, uint8_t level);
static void espi_vw_send_bootload_done(const struct device *dev);
#if defined(CONFIG_ESPI_FLASH_CHANNEL)
static int espi_npcx_flash_parse_completion_with_data(const struct device *dev,
struct espi_flash_packet *pckt);
static void espi_npcx_flash_prepare_tx_header(const struct device *dev, int cyc_type,
int flash_addr, int flash_len, int tx_payload);
#endif
/* eSPI local initialization functions */
static void espi_init_wui_callback(const struct device *dev,
struct miwu_callback *callback, const struct npcx_wui *wui,
@ -232,6 +243,20 @@ static void espi_bus_reset_isr(const struct device *dev)
/* Do nothing! This signal is handled in ESPI_RST VW signal ISR */
}
#if defined(CONFIG_ESPI_NPCX_CAF_GLOBAL_RESET_WORKAROUND)
static void espi_npcx_flash_fake_request(const struct device *dev)
{
struct espi_reg *const inst = HAL_INSTANCE(dev);
struct espi_npcx_data *const data = dev->data;
inst->FLASHCTL &= ~BIT(NPCX_FLASHCTL_AMTEN);
data->fake_req_flag = true;
espi_npcx_flash_prepare_tx_header(dev, ESPI_FLASH_READ_CYCLE_TYPE, 0, 16, 0);
}
#endif
static void espi_bus_cfg_update_isr(const struct device *dev)
{
int chan;
@ -259,6 +284,13 @@ static void espi_bus_cfg_update_isr(const struct device *dev)
NPCX_ESPI_HOST_CH_EN(chan));
evt.evt_details = BIT(chan);
#if defined(CONFIG_ESPI_NPCX_CAF_GLOBAL_RESET_WORKAROUND)
if (chan == NPCX_ESPI_CH_FLASH && evt.evt_data == 1 &&
IS_BIT_SET(inst->FLASHCTL, NPCX_FLASHCTL_FLASH_TX_AVAIL)) {
espi_npcx_flash_fake_request(dev);
}
#endif
if (evt.evt_data) {
inst->ESPICFG |= BIT(chan);
} else {
@ -358,6 +390,17 @@ static void espi_bus_flash_rx_isr(const struct device *dev)
/* Controller Attached Flash Access */
if ((inst->ESPICFG & BIT(NPCX_ESPICFG_FLCHANMODE)) == 0) {
#ifdef CONFIG_ESPI_NPCX_CAF_GLOBAL_RESET_WORKAROUND
if (data->fake_req_flag == true) {
uint8_t pckt_buf[16];
struct espi_flash_packet pckt;
pckt.buf = &pckt_buf[0];
espi_npcx_flash_parse_completion_with_data(dev, &pckt);
data->fake_req_flag = false;
return;
}
#endif
k_sem_give(&data->flash_rx_lock);
} else { /* Target Attached Flash Access */
#if defined(CONFIG_ESPI_SAF)