/* * Copyright (c) 2020 Nuvoton Technology Corporation. * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT nuvoton_npcx_espi #include #include #include #include #include #include #include #include #include #include #include #include "espi_utils.h" #include "soc_host.h" #include "soc_miwu.h" #include #include LOG_MODULE_REGISTER(espi, CONFIG_ESPI_LOG_LEVEL); struct espi_npcx_config { uintptr_t base; /* clock configuration */ struct npcx_clk_cfg clk_cfg; /* mapping table between eSPI reset signal and wake-up input */ struct npcx_wui espi_rst_wui; /* pinmux configuration */ const struct pinctrl_dev_config *pcfg; }; struct espi_npcx_data { sys_slist_t callbacks; uint8_t plt_rst_asserted; uint8_t espi_rst_level; uint8_t sx_state; #if !defined(CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC) struct k_sem oob_rx_lock; #endif #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 }; #if DT_NODE_HAS_PROP(DT_DRV_INST(0), vw_index_extend_set) struct espi_npcx_vw_ex { uint8_t direction; uint8_t group_num; uint8_t index; }; /* n = node, p = property, i = index */ #define ESPI_NPCX_VW_EX_INFO(n, p, i) \ { \ .index = ESPI_NPCX_VW_EX_INDEX(DT_PROP_BY_IDX(n, p, i)), \ .group_num = ESPI_NPCX_VW_EX_GROUP_NUM(DT_PROP_BY_IDX(n, p, i)), \ .direction = ESPI_NPCX_VW_EX_DIR(DT_PROP_BY_IDX(n, p, i)), \ }, static const struct espi_npcx_vw_ex espi_npcx_vw_ex_0[] = { DT_FOREACH_PROP_ELEM(DT_DRV_INST(0), vw_index_extend_set, ESPI_NPCX_VW_EX_INFO) }; #endif /* Driver convenience defines */ #define HAL_INSTANCE(dev) \ ((struct espi_reg *)((const struct espi_npcx_config *)(dev)->config)->base) /* eSPI channels */ #define NPCX_ESPI_CH_PC 0 #define NPCX_ESPI_CH_VW 1 #define NPCX_ESPI_CH_OOB 2 #define NPCX_ESPI_CH_FLASH 3 #define NPCX_ESPI_CH_COUNT 4 #define NPCX_ESPI_HOST_CH_EN(ch) (ch + 4) /* eSPI max supported frequency */ #define NPCX_ESPI_MAXFREQ_20 0 #define NPCX_ESPI_MAXFREQ_25 1 #define NPCX_ESPI_MAXFREQ_33 2 #define NPCX_ESPI_MAXFREQ_50 3 #define NPCX_ESPI_MAXFREQ_66 4 /* Minimum delay before acknowledging a virtual wire */ #define NPCX_ESPI_VWIRE_ACK_DELAY 10ul /* 10 us */ /* OOB channel maximum payload size */ #define NPCX_ESPI_OOB_MAX_PAYLOAD 64 #define NPCX_OOB_RX_PACKAGE_LEN(hdr) (((hdr & 0xff000000) >> 24) | \ ((hdr & 0xf0000) >> 8)) /* Flash channel maximum payload size */ #define NPCX_ESPI_FLASH_MAX_RX_PAYLOAD DT_INST_PROP(0, rx_plsize) #define NPCX_ESPI_FLASH_MAX_TX_PAYLOAD DT_INST_PROP(0, tx_plsize) /* eSPI cycle type field for OOB and FLASH channels */ #define ESPI_FLASH_READ_CYCLE_TYPE 0x00 #define ESPI_FLASH_WRITE_CYCLE_TYPE 0x01 #define ESPI_FLASH_ERASE_CYCLE_TYPE 0x02 #define ESPI_FLASH_SUCCESS_WITH_DATA_CYCLE_TYPE 0x0f #define ESPI_FLASH_SUCCESS_WITHOUT_DATA_CYCLE_TYPE 0x06 #define ESPI_FLASH_HEADER_PCKT_SIZE 0x07 #define ESPI_FLASH_MAX_TIMEOUT 1000ul /* 1000 ms */ #define ESPI_OOB_GET_CYCLE_TYPE 0x21 #define ESPI_OOB_TAG 0x00 #define ESPI_OOB_MAX_TIMEOUT 500ul /* 500 ms */ /* eSPI bus interrupt configuration structure and macro function */ struct espi_bus_isr { uint8_t status_bit; /* bit order in ESPISTS register */ uint8_t int_en_bit; /* bit order in ESPIIE register */ uint8_t wake_en_bit; /* bit order in ESPIWE register */ void (*bus_isr)(const struct device *dev); /* eSPI bus ISR */ }; #define NPCX_ESPI_BUS_INT_ITEM(event, isr) { \ .status_bit = NPCX_ESPISTS_##event, \ .int_en_bit = NPCX_ESPIIE_##event##IE, \ .wake_en_bit = NPCX_ESPIWE_##event##WE, \ .bus_isr = isr } /* eSPI Virtual Wire Input (Master-to-Slave) signals configuration structure */ struct npcx_vw_in_config { enum espi_vwire_signal sig; /* Virtual Wire signal */ uint8_t reg_idx; /* register index for VW signal */ uint8_t bitmask; /* VW signal bits-mask */ struct npcx_wui vw_wui; /* WUI mapping in MIWU modules for VW signal */ }; /* eSPI Virtual Wire Output (Slave-to-Master) signals configuration structure */ struct npcx_vw_out_config { enum espi_vwire_signal sig; /* Virtual Wire signal */ uint8_t reg_idx; /* register index for VW signal */ uint8_t bitmask; /* VW signal bits-mask */ }; /* * eSPI VW input/Output signal configuration tables. Please refer * npcxn-espi-vws-map.dtsi device tree file for more detail. */ static const struct npcx_vw_in_config vw_in_tbl[] = { /* index 02h (In) */ NPCX_DT_VW_IN_CONF(ESPI_VWIRE_SIGNAL_SLP_S3, vw_slp_s3), NPCX_DT_VW_IN_CONF(ESPI_VWIRE_SIGNAL_SLP_S4, vw_slp_s4), NPCX_DT_VW_IN_CONF(ESPI_VWIRE_SIGNAL_SLP_S5, vw_slp_s5), /* index 03h (In) */ NPCX_DT_VW_IN_CONF(ESPI_VWIRE_SIGNAL_SUS_STAT, vw_sus_stat), NPCX_DT_VW_IN_CONF(ESPI_VWIRE_SIGNAL_PLTRST, vw_plt_rst), NPCX_DT_VW_IN_CONF(ESPI_VWIRE_SIGNAL_OOB_RST_WARN, vw_oob_rst_warn), /* index 07h (In) */ NPCX_DT_VW_IN_CONF(ESPI_VWIRE_SIGNAL_HOST_RST_WARN, vw_host_rst_warn), /* index 41h (In) */ NPCX_DT_VW_IN_CONF(ESPI_VWIRE_SIGNAL_SUS_WARN, vw_sus_warn), NPCX_DT_VW_IN_CONF(ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK, vw_sus_pwrdn_ack), NPCX_DT_VW_IN_CONF(ESPI_VWIRE_SIGNAL_SLP_A, vw_slp_a), /* index 42h (In) */ NPCX_DT_VW_IN_CONF(ESPI_VWIRE_SIGNAL_SLP_LAN, vw_slp_lan), NPCX_DT_VW_IN_CONF(ESPI_VWIRE_SIGNAL_SLP_WLAN, vw_slp_wlan), #if DT_NODE_EXISTS(DT_CHILD(DT_PATH(npcx_espi_vws_map), vw_dnx_warn)) /* index 4Ah (In) */ NPCX_DT_VW_IN_CONF(ESPI_VWIRE_SIGNAL_DNX_WARN, vw_dnx_warn), #endif }; static const struct npcx_vw_out_config vw_out_tbl[] = { /* index 04h (Out) */ NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_OOB_RST_ACK, vw_oob_rst_ack), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_WAKE, vw_wake), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_PME, vw_pme), /* index 05h (Out) */ NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, vw_slv_boot_done), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_ERR_FATAL, vw_err_fatal), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_ERR_NON_FATAL, vw_err_non_fatal), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, vw_slv_boot_sts_with_done), /* index 06h (Out) */ NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_SCI, vw_sci), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_SMI, vw_smi), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_HOST_RST_ACK, vw_host_rst_ack), /* index 40h (Out) */ NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_SUS_ACK, vw_sus_ack), #if DT_NODE_EXISTS(DT_CHILD(DT_PATH(npcx_espi_vws_map), vw_dnx_ack)) NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_DNX_ACK, vw_dnx_ack), #endif }; /* Virtual wire GPIOs for platform level usage (High at Reset state) */ static const struct npcx_vw_out_config vw_out_gpio_tbl1[] = { /* Only NPCX9 and later series support this feature */ #if defined(CONFIG_ESPI_NPCX_SUPP_VW_GPIO) /* index 50h (Out) */ NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_0, vw_slv_gpio_0), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_1, vw_slv_gpio_1), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_2, vw_slv_gpio_2), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_3, vw_slv_gpio_3), /* index 51h (Out) */ NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_4, vw_slv_gpio_4), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_5, vw_slv_gpio_5), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_6, vw_slv_gpio_6), NPCX_DT_VW_OUT_CONF(ESPI_VWIRE_SIGNAL_TARGET_GPIO_7, vw_slv_gpio_7), #endif }; /* Callbacks for eSPI bus reset and Virtual Wire signals. */ static struct miwu_callback espi_rst_callback; static struct miwu_callback vw_in_callback[ARRAY_SIZE(vw_in_tbl)]; /* eSPI VW service function forward declarations */ static int espi_npcx_receive_vwire(const struct device *dev, enum espi_vwire_signal signal, uint8_t *level); 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, miwu_dev_callback_handler_t handler) { /* VW signal which has no wake-up input source */ if (wui->table == NPCX_MIWU_TABLE_NONE) { return; } /* Install callback function */ npcx_miwu_init_dev_callback(callback, wui, handler, dev); npcx_miwu_manage_callback(callback, 1); /* Configure MIWU setting and enable its interrupt */ npcx_miwu_interrupt_configure(wui, NPCX_MIWU_MODE_EDGE, NPCX_MIWU_TRIG_BOTH); } /* eSPI local bus interrupt service functions */ static void espi_bus_err_isr(const struct device *dev) { struct espi_reg *const inst = HAL_INSTANCE(dev); uint32_t err = inst->ESPIERR; LOG_ERR("eSPI Bus Error %08X", err); /* Clear error status bits */ inst->ESPIERR = err; } static void espi_bus_inband_rst_isr(const struct device *dev) { ARG_UNUSED(dev); LOG_DBG("%s issued", __func__); } static void espi_bus_reset_isr(const struct device *dev) { ARG_UNUSED(dev); LOG_DBG("%s issued", __func__); /* 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; struct espi_reg *const inst = HAL_INSTANCE(dev); struct espi_npcx_data *const data = dev->data; struct espi_event evt = { .evt_type = ESPI_BUS_EVENT_CHANNEL_READY, .evt_details = 0, .evt_data = 0 }; /* If host enable bits are not sync with ready bits on slave side. */ uint8_t chg_mask = GET_FIELD(inst->ESPICFG, NPCX_ESPICFG_HCHANS_FIELD) ^ GET_FIELD(inst->ESPICFG, NPCX_ESPICFG_CHANS_FIELD); chg_mask &= (ESPI_CHANNEL_VWIRE | ESPI_CHANNEL_OOB | ESPI_CHANNEL_FLASH); LOG_DBG("ESPI CFG Change Updated! 0x%02X", chg_mask); /* * If host enable/disable channel for VW/OOB/FLASH, EC should follow * except Peripheral channel. It is handled after receiving PLTRST * event separately. */ for (chan = NPCX_ESPI_CH_VW; chan < NPCX_ESPI_CH_COUNT; chan++) { /* Channel ready bit isn't sync with enabled bit on host side */ if (chg_mask & BIT(chan)) { evt.evt_data = IS_BIT_SET(inst->ESPICFG, 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 { inst->ESPICFG &= ~BIT(chan); } espi_send_callbacks(&data->callbacks, dev, evt); } } LOG_DBG("ESPI CFG EC Updated! 0x%02X", GET_FIELD(inst->ESPICFG, NPCX_ESPICFG_CHANS_FIELD)); /* If VW channel is enabled and ready, send bootload done VW signal */ if ((chg_mask & BIT(NPCX_ESPI_CH_VW)) && IS_BIT_SET(inst->ESPICFG, NPCX_ESPI_HOST_CH_EN(NPCX_ESPI_CH_VW))) { espi_vw_send_bootload_done(dev); } #if (defined(CONFIG_ESPI_FLASH_CHANNEL) && defined(CONFIG_ESPI_TAF)) /* If CONFIG_ESPI_TAF is set, set to auto or manual mode accroding * to configuration. */ if (IS_BIT_SET(inst->ESPICFG, NPCX_ESPICFG_FLCHANMODE)) { #if defined(CONFIG_ESPI_TAF_AUTO_MODE) inst->FLASHCTL |= BIT(NPCX_FLASHCTL_SAF_AUTO_READ); #else inst->FLASHCTL &= ~BIT(NPCX_FLASHCTL_SAF_AUTO_READ); #endif } #endif } #if defined(CONFIG_ESPI_OOB_CHANNEL) static void espi_bus_oob_rx_isr(const struct device *dev) { struct espi_npcx_data *const data = dev->data; #if defined(CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC) struct espi_reg *const inst = HAL_INSTANCE(dev); struct espi_event evt = { .evt_type = ESPI_BUS_EVENT_OOB_RECEIVED, .evt_details = 0, .evt_data = 0, }; /* Get received package length and set to additional detail of event */ evt.evt_details = NPCX_OOB_RX_PACKAGE_LEN(inst->OOBRXBUF[0]); espi_send_callbacks(&data->callbacks, dev, evt); #else LOG_DBG("%s", __func__); k_sem_give(&data->oob_rx_lock); #endif } #endif #if defined(CONFIG_ESPI_FLASH_CHANNEL) #if defined(CONFIG_ESPI_TAF) static struct espi_taf_pckt taf_pckt; static uint32_t espi_taf_parse(const struct device *dev) { struct espi_reg *const inst = HAL_INSTANCE(dev); struct npcx_taf_head taf_head; uint32_t taf_addr, head_data; uint8_t i, roundsize; /* Get type, length and tag from RX buffer */ head_data = inst->FLASHRXBUF[0]; taf_head = *(struct npcx_taf_head *)&head_data; taf_pckt.type = taf_head.type; taf_pckt.len = (((uint16_t)taf_head.tag_hlen & 0xF) << 8) | taf_head.llen; taf_pckt.tag = taf_head.tag_hlen >> 4; if ((taf_pckt.len == 0) && (taf_pckt.type == NPCX_ESPI_TAF_REQ_READ)) { taf_pckt.len = KB(4); } /* Get address from RX buffer */ taf_addr = inst->FLASHRXBUF[1]; taf_pckt.addr = sys_cpu_to_be32(taf_addr); /* Get written data if eSPI TAF write or RPMC OP1 */ if ((taf_pckt.type == NPCX_ESPI_TAF_REQ_WRITE) || (IS_ENABLED(CONFIG_ESPI_TAF_NPCX_RPMC_SUPPORT) && (taf_pckt.type == NPCX_ESPI_TAF_REQ_RPMC_OP1))) { roundsize = DIV_ROUND_UP(taf_pckt.len, sizeof(uint32_t)); for (i = 0; i < roundsize; i++) { taf_pckt.src[i] = inst->FLASHRXBUF[2 + i]; } } return (uint32_t)&taf_pckt; } #endif /* CONFIG_ESPI_TAF */ static void espi_bus_flash_rx_isr(const struct device *dev) { struct espi_reg *const inst = HAL_INSTANCE(dev); struct espi_npcx_data *const data = dev->data; /* 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_TAF) struct espi_event evt = { .evt_type = ESPI_BUS_TAF_NOTIFICATION, .evt_details = ESPI_CHANNEL_FLASH, .evt_data = espi_taf_parse(dev), }; espi_send_callbacks(&data->callbacks, dev, evt); #else LOG_WRN("ESPI TAF not supported"); #endif } } #endif /* CONFIG_ESPI_FLASH_CHANNEL */ const struct espi_bus_isr espi_bus_isr_tbl[] = { NPCX_ESPI_BUS_INT_ITEM(BERR, espi_bus_err_isr), NPCX_ESPI_BUS_INT_ITEM(IBRST, espi_bus_inband_rst_isr), NPCX_ESPI_BUS_INT_ITEM(ESPIRST, espi_bus_reset_isr), NPCX_ESPI_BUS_INT_ITEM(CFGUPD, espi_bus_cfg_update_isr), #if defined(CONFIG_ESPI_OOB_CHANNEL) NPCX_ESPI_BUS_INT_ITEM(OOBRX, espi_bus_oob_rx_isr), #endif #if defined(CONFIG_ESPI_FLASH_CHANNEL) NPCX_ESPI_BUS_INT_ITEM(FLASHRX, espi_bus_flash_rx_isr), #endif }; static void espi_bus_generic_isr(const struct device *dev) { struct espi_reg *const inst = HAL_INSTANCE(dev); int i; uint32_t mask, status; /* * Bit 17 of ESPIIE is reserved. We need to set the same bit in mask * in case bit 17 in ESPISTS of npcx7 is not cleared in ISR. */ mask = inst->ESPIIE | (1 << NPCX_ESPISTS_VWUPDW); status = inst->ESPISTS & mask; /* Clear pending bits of status register first */ inst->ESPISTS = status; LOG_DBG("%s: 0x%08X", __func__, status); for (i = 0; i < ARRAY_SIZE(espi_bus_isr_tbl); i++) { struct espi_bus_isr entry = espi_bus_isr_tbl[i]; if (status & BIT(entry.status_bit)) { if (entry.bus_isr != NULL) { entry.bus_isr(dev); } } } } /* eSPI local virtual-wire service functions */ static void espi_vw_config_input(const struct device *dev, const struct npcx_vw_in_config *config_in) { struct espi_reg *const inst = HAL_INSTANCE(dev); int idx = config_in->reg_idx; /* IE & WE bits are already set? */ if (IS_BIT_SET(inst->VWEVMS[idx], NPCX_VWEVMS_IE) && IS_BIT_SET(inst->VWEVMS[idx], NPCX_VWEVMS_WE)) { return; } /* Set IE & WE bits in VWEVMS */ inst->VWEVMS[idx] |= BIT(NPCX_VWEVMS_IE) | BIT(NPCX_VWEVMS_WE); LOG_DBG("VWEVMS%d 0x%08X", idx, inst->VWEVMS[idx]); } static void espi_vw_config_output(const struct device *dev, const struct npcx_vw_out_config *config_out) { struct espi_reg *const inst = HAL_INSTANCE(dev); int idx = config_out->reg_idx; uint8_t valid = GET_FIELD(inst->VWEVSM[idx], NPCX_VWEVSM_VALID); /* Set valid bits for vw signal which we have declared in table. */ valid |= config_out->bitmask; SET_FIELD(inst->VWEVSM[idx], NPCX_VWEVSM_VALID, valid); /* * Turn off hardware-wire feature which generates VW events that * connected to hardware signals. We will set it manually by software. */ SET_FIELD(inst->VWEVSM[idx], NPCX_VWEVSM_HW_WIRE, 0); LOG_DBG("VWEVSM%d 0x%08X", idx, inst->VWEVSM[idx]); } static void espi_vw_gpio_config_output(const struct device *dev, const struct npcx_vw_out_config *config_out, uint8_t init_level) { struct espi_reg *const inst = HAL_INSTANCE(dev); int idx = config_out->reg_idx; uint8_t valid = GET_FIELD(inst->VWGPSM[idx], NPCX_VWEVSM_VALID); uint8_t val = GET_FIELD(inst->VWGPSM[idx], NPCX_VWEVSM_WIRE); /* Set valid bits for vw signal which we have declared in table. */ valid |= config_out->bitmask; SET_FIELD(inst->VWGPSM[idx], NPCX_VWEVSM_VALID, valid); inst->VWGPSM[idx] |= BIT(NPCX_VWGPSM_INDEX_EN); if (init_level) { val |= config_out->bitmask; } else { val &= ~config_out->bitmask; } SET_FIELD(inst->VWGPSM[idx], NPCX_VWEVSM_WIRE, val); LOG_DBG("VWEVSM%d 0x%08X", idx, inst->VWGPSM[idx]); } static void espi_vw_notify_system_state(const struct device *dev, enum espi_vwire_signal signal) { struct espi_npcx_data *const data = dev->data; struct espi_event evt = { ESPI_BUS_EVENT_VWIRE_RECEIVED, 0, 0 }; uint8_t wire = 0; espi_npcx_receive_vwire(dev, signal, &wire); if (!wire) { data->sx_state = signal; } evt.evt_details = signal; evt.evt_data = wire; espi_send_callbacks(&data->callbacks, dev, evt); } static void espi_vw_notify_host_warning(const struct device *dev, enum espi_vwire_signal signal) { uint8_t wire; espi_npcx_receive_vwire(dev, signal, &wire); k_busy_wait(NPCX_ESPI_VWIRE_ACK_DELAY); switch (signal) { case ESPI_VWIRE_SIGNAL_HOST_RST_WARN: espi_npcx_send_vwire(dev, ESPI_VWIRE_SIGNAL_HOST_RST_ACK, wire); break; case ESPI_VWIRE_SIGNAL_SUS_WARN: espi_npcx_send_vwire(dev, ESPI_VWIRE_SIGNAL_SUS_ACK, wire); break; case ESPI_VWIRE_SIGNAL_OOB_RST_WARN: espi_npcx_send_vwire(dev, ESPI_VWIRE_SIGNAL_OOB_RST_ACK, wire); break; #if DT_NODE_EXISTS(DT_CHILD(DT_PATH(npcx_espi_vws_map), vw_dnx_warn)) case ESPI_VWIRE_SIGNAL_DNX_WARN: espi_npcx_send_vwire(dev, ESPI_VWIRE_SIGNAL_DNX_ACK, wire); break; #endif default: break; } } static void espi_vw_notify_plt_rst(const struct device *dev) { struct espi_npcx_data *const data = dev->data; struct espi_reg *const inst = HAL_INSTANCE(dev); struct espi_event evt = { ESPI_BUS_EVENT_VWIRE_RECEIVED, ESPI_VWIRE_SIGNAL_PLTRST, 0 }; uint8_t wire = 0; espi_npcx_receive_vwire(dev, ESPI_VWIRE_SIGNAL_PLTRST, &wire); LOG_DBG("VW_PLT_RST is %d!", wire); if (wire) { /* Set Peripheral Channel ready when PLTRST is de-asserted */ inst->ESPICFG |= BIT(NPCX_ESPICFG_PCHANEN); /* Configure all host sub-modules in host domain */ npcx_host_init_subs_host_domain(); } /* PLT_RST will be received several times */ if (wire != data->plt_rst_asserted) { data->plt_rst_asserted = wire; evt.evt_data = wire; espi_send_callbacks(&data->callbacks, dev, evt); } } static void espi_vw_send_bootload_done(const struct device *dev) { int ret; uint8_t boot_done; ret = espi_npcx_receive_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, &boot_done); LOG_DBG("%s: %d", __func__, boot_done); if (!ret && !boot_done) { /* Send slave boot status bit with done bit at the same time. */ espi_npcx_send_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, 1); } } static void espi_vw_generic_isr(const struct device *dev, struct npcx_wui *wui) { int idx; enum espi_vwire_signal signal; LOG_DBG("%s: WUI %d %d %d", __func__, wui->table, wui->group, wui->bit); for (idx = 0; idx < ARRAY_SIZE(vw_in_tbl); idx++) { if (wui->table == vw_in_tbl[idx].vw_wui.table && wui->group == vw_in_tbl[idx].vw_wui.group && wui->bit == vw_in_tbl[idx].vw_wui.bit) { break; } } if (idx == ARRAY_SIZE(vw_in_tbl)) { LOG_ERR("Unknown VW event! %d %d %d", wui->table, wui->group, wui->bit); return; } signal = vw_in_tbl[idx].sig; if (signal == ESPI_VWIRE_SIGNAL_SLP_S3 || signal == ESPI_VWIRE_SIGNAL_SLP_S4 || signal == ESPI_VWIRE_SIGNAL_SLP_S5 || signal == ESPI_VWIRE_SIGNAL_SLP_A) { espi_vw_notify_system_state(dev, signal); #if DT_NODE_EXISTS(DT_CHILD(DT_PATH(npcx_espi_vws_map), vw_dnx_warn)) } else if (signal == ESPI_VWIRE_SIGNAL_HOST_RST_WARN || signal == ESPI_VWIRE_SIGNAL_SUS_WARN || signal == ESPI_VWIRE_SIGNAL_OOB_RST_WARN || signal == ESPI_VWIRE_SIGNAL_DNX_WARN) { #else } else if (signal == ESPI_VWIRE_SIGNAL_HOST_RST_WARN || signal == ESPI_VWIRE_SIGNAL_SUS_WARN || signal == ESPI_VWIRE_SIGNAL_OOB_RST_WARN) { #endif espi_vw_notify_host_warning(dev, signal); } else if (signal == ESPI_VWIRE_SIGNAL_PLTRST) { espi_vw_notify_plt_rst(dev); } } static void espi_vw_espi_rst_isr(const struct device *dev, struct npcx_wui *wui) { struct espi_reg *const inst = HAL_INSTANCE(dev); struct espi_npcx_data *const data = dev->data; struct espi_event evt = { ESPI_BUS_RESET, 0, 0 }; data->espi_rst_level = IS_BIT_SET(inst->ESPISTS, NPCX_ESPISTS_ESPIRST_LVL); LOG_DBG("eSPI RST level is %d!", data->espi_rst_level); evt.evt_data = data->espi_rst_level; espi_send_callbacks(&data->callbacks, dev, evt); } /* eSPI api functions */ static int espi_npcx_configure(const struct device *dev, struct espi_cfg *cfg) { struct espi_reg *const inst = HAL_INSTANCE(dev); uint8_t max_freq = 0; uint8_t cur_io_mode, io_mode = 0; /* Configure eSPI frequency */ switch (cfg->max_freq) { case 20: max_freq = NPCX_ESPI_MAXFREQ_20; break; case 25: max_freq = NPCX_ESPI_MAXFREQ_25; break; case 33: max_freq = NPCX_ESPI_MAXFREQ_33; break; case 50: max_freq = NPCX_ESPI_MAXFREQ_50; break; #ifdef CONFIG_SOC_SERIES_NPCX4 case 66: max_freq = NPCX_ESPI_MAXFREQ_66; break; #endif default: return -EINVAL; } SET_FIELD(inst->ESPICFG, NPCX_ESPICFG_MAXFREQ_FIELD, max_freq); /* Configure eSPI IO mode */ io_mode = (cfg->io_caps >> 1); if (io_mode > 3) { return -EINVAL; } cur_io_mode = GET_FIELD(inst->ESPICFG, NPCX_ESPICFG_IOMODE_FIELD); if (io_mode != cur_io_mode) { SET_FIELD(inst->ESPICFG, NPCX_ESPICFG_IOMODE_FIELD, io_mode); } /* Configure eSPI supported channels */ if (cfg->channel_caps & ESPI_CHANNEL_PERIPHERAL) { inst->ESPICFG |= BIT(NPCX_ESPICFG_PCCHN_SUPP); } if (cfg->channel_caps & ESPI_CHANNEL_VWIRE) { inst->ESPICFG |= BIT(NPCX_ESPICFG_VWCHN_SUPP); } if (cfg->channel_caps & ESPI_CHANNEL_OOB) { inst->ESPICFG |= BIT(NPCX_ESPICFG_OOBCHN_SUPP); } if (cfg->channel_caps & ESPI_CHANNEL_FLASH) { inst->ESPICFG |= BIT(NPCX_ESPICFG_FLASHCHN_SUPP); } LOG_DBG("%s: %d %d ESPICFG: 0x%08X", __func__, max_freq, io_mode, inst->ESPICFG); return 0; } static bool espi_npcx_channel_ready(const struct device *dev, enum espi_channel ch) { struct espi_reg *const inst = HAL_INSTANCE(dev); bool sts; switch (ch) { case ESPI_CHANNEL_PERIPHERAL: sts = IS_BIT_SET(inst->ESPICFG, NPCX_ESPICFG_PCHANEN); break; case ESPI_CHANNEL_VWIRE: sts = IS_BIT_SET(inst->ESPICFG, NPCX_ESPICFG_VWCHANEN); break; case ESPI_CHANNEL_OOB: sts = IS_BIT_SET(inst->ESPICFG, NPCX_ESPICFG_OOBCHANEN); break; case ESPI_CHANNEL_FLASH: sts = IS_BIT_SET(inst->ESPICFG, NPCX_ESPICFG_FLASHCHANEN); break; default: sts = false; break; } return sts; } static int espi_npcx_send_vwire(const struct device *dev, enum espi_vwire_signal signal, uint8_t level) { uint8_t reg_idx, bitmask, sig_idx, val = 0, vw_tbl_size; struct espi_reg *const inst = HAL_INSTANCE(dev); const struct npcx_vw_out_config *vw_tbl; uint32_t reg_val; char *reg_name; if (signal >= ESPI_VWIRE_SIGNAL_COUNT) { LOG_ERR("Invalid VW: %d", signal); return -EINVAL; } if (signal >= ESPI_VWIRE_SIGNAL_TARGET_GPIO_0) { vw_tbl = vw_out_gpio_tbl1; vw_tbl_size = ARRAY_SIZE(vw_out_gpio_tbl1); reg_name = "VWGPSM"; } else { vw_tbl = vw_out_tbl; vw_tbl_size = ARRAY_SIZE(vw_out_tbl); reg_name = "VWEVSM"; } /* Find signal in VW output table */ for (sig_idx = 0; sig_idx < vw_tbl_size; sig_idx++) { if (vw_tbl[sig_idx].sig == signal) { break; } } if (sig_idx == vw_tbl_size) { LOG_ERR("%s signal %d is invalid", __func__, signal); return -EIO; } reg_idx = vw_tbl[sig_idx].reg_idx; bitmask = vw_tbl[sig_idx].bitmask; /* Get wire field and set/clear wire bit */ if (signal >= ESPI_VWIRE_SIGNAL_TARGET_GPIO_0) { val = GET_FIELD(inst->VWGPSM[reg_idx], NPCX_VWEVSM_WIRE); } else { val = GET_FIELD(inst->VWEVSM[reg_idx], NPCX_VWEVSM_WIRE); } if (level) { val |= bitmask; } else { val &= ~bitmask; } if (signal >= ESPI_VWIRE_SIGNAL_TARGET_GPIO_0) { SET_FIELD(inst->VWGPSM[reg_idx], NPCX_VWEVSM_WIRE, val); reg_val = inst->VWGPSM[reg_idx]; } else { SET_FIELD(inst->VWEVSM[reg_idx], NPCX_VWEVSM_WIRE, val); reg_val = inst->VWEVSM[reg_idx]; } LOG_DBG("Send VW: %s%d 0x%08X", reg_name, reg_idx, reg_val); return 0; } static int espi_npcx_receive_vwire(const struct device *dev, enum espi_vwire_signal signal, uint8_t *level) { struct espi_reg *const inst = HAL_INSTANCE(dev); uint8_t reg_idx, bitmask, sig_idx, val; /* Find signal in VW input table */ for (sig_idx = 0; sig_idx < ARRAY_SIZE(vw_in_tbl); sig_idx++) { if (vw_in_tbl[sig_idx].sig == signal) { reg_idx = vw_in_tbl[sig_idx].reg_idx; bitmask = vw_in_tbl[sig_idx].bitmask; val = GET_FIELD(inst->VWEVMS[reg_idx], NPCX_VWEVMS_WIRE); if (IS_ENABLED(CONFIG_ESPI_VWIRE_VALID_BIT_CHECK)) { val &= GET_FIELD(inst->VWEVMS[reg_idx], NPCX_VWEVMS_VALID); } *level = !!(val & bitmask); return 0; } } /* Find signal in VW output table */ for (sig_idx = 0; sig_idx < ARRAY_SIZE(vw_out_tbl); sig_idx++) { if (vw_out_tbl[sig_idx].sig == signal) { reg_idx = vw_out_tbl[sig_idx].reg_idx; bitmask = vw_out_tbl[sig_idx].bitmask; val = GET_FIELD(inst->VWEVSM[reg_idx], NPCX_VWEVSM_WIRE); if (IS_ENABLED(CONFIG_ESPI_VWIRE_VALID_BIT_CHECK)) { val &= GET_FIELD(inst->VWEVSM[reg_idx], NPCX_VWEVSM_VALID); } *level = !!(val & bitmask); return 0; } } LOG_ERR("%s Out of index %d", __func__, signal); return -EIO; } static int espi_npcx_manage_callback(const struct device *dev, struct espi_callback *callback, bool set) { struct espi_npcx_data *const data = dev->data; return espi_manage_callback(&data->callbacks, callback, set); } static int espi_npcx_read_lpc_request(const struct device *dev, enum lpc_peripheral_opcode op, uint32_t *data) { ARG_UNUSED(dev); return npcx_host_periph_read_request(op, data); } static int espi_npcx_write_lpc_request(const struct device *dev, enum lpc_peripheral_opcode op, uint32_t *data) { ARG_UNUSED(dev); return npcx_host_periph_write_request(op, data); } #if defined(CONFIG_ESPI_OOB_CHANNEL) static int espi_npcx_send_oob(const struct device *dev, struct espi_oob_packet *pckt) { struct espi_reg *const inst = HAL_INSTANCE(dev); uint8_t *oob_buf = pckt->buf; int sz_oob_tx = pckt->len; int idx_tx_buf; uint32_t oob_data; /* Check out of OOB transmitted buffer size */ if (sz_oob_tx > NPCX_ESPI_OOB_MAX_PAYLOAD) { LOG_ERR("Out of OOB transmitted buffer: %d", sz_oob_tx); return -EINVAL; } /* Check OOB Transmit Queue is empty? */ if (IS_BIT_SET(inst->OOBCTL, NPCX_OOBCTL_OOB_AVAIL)) { LOG_ERR("OOB channel is busy"); return -EBUSY; } /* * GET_OOB header (first 4 bytes) in npcx 32-bits tx buffer * * [24:31] - LEN[0:7] Data length of GET_OOB request package * [20:23] - TAG Tag of GET_OOB * [16:19] - LEN[8:11] Ignore it since max payload is 64 bytes * [8:15] - CYCLE_TYPE Cycle type of GET_OOB * [0:7] - SZ_PACK Package size plus 3 bytes header. (Npcx only) */ inst->OOBTXBUF[0] = (sz_oob_tx + 3) | (ESPI_OOB_GET_CYCLE_TYPE << 8) | (ESPI_OOB_TAG << 16) | (sz_oob_tx << 24); /* Write GET_OOB data into 32-bits tx buffer in little endian */ for (idx_tx_buf = 0; idx_tx_buf < sz_oob_tx/4; idx_tx_buf++, oob_buf += 4) inst->OOBTXBUF[idx_tx_buf + 1] = oob_buf[0] | (oob_buf[1] << 8) | (oob_buf[2] << 16) | (oob_buf[3] << 24); /* Write remaining bytes of package */ if (sz_oob_tx % 4) { int i; oob_data = 0; for (i = 0; i < sz_oob_tx % 4; i++) { oob_data |= (oob_buf[i] << (8 * i)); } inst->OOBTXBUF[idx_tx_buf + 1] = oob_data; } /* * Notify host a new OOB packet is ready. Please don't write OOB_FREE * to 1 at the same tiem in case clear it unexpectedly. */ oob_data = inst->OOBCTL & ~(BIT(NPCX_OOBCTL_OOB_FREE)); oob_data |= BIT(NPCX_OOBCTL_OOB_AVAIL); inst->OOBCTL = oob_data; while (IS_BIT_SET(inst->OOBCTL, NPCX_OOBCTL_OOB_AVAIL)) { ; } LOG_DBG("%s issued!!", __func__); return 0; } static int espi_npcx_receive_oob(const struct device *dev, struct espi_oob_packet *pckt) { struct espi_reg *const inst = HAL_INSTANCE(dev); uint8_t *oob_buf = pckt->buf; uint32_t oob_data; int idx_rx_buf, sz_oob_rx; /* Check eSPI bus status first */ if (IS_BIT_SET(inst->ESPISTS, NPCX_ESPISTS_BERR)) { LOG_ERR("%s: eSPI Bus Error: 0x%08X", __func__, inst->ESPIERR); return -EIO; } #if !defined(CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC) struct espi_npcx_data *const data = dev->data; int ret; /* Wait until get oob package or timeout */ ret = k_sem_take(&data->oob_rx_lock, K_MSEC(ESPI_OOB_MAX_TIMEOUT)); if (ret == -EAGAIN) { LOG_ERR("%s: Timeout", __func__); return -ETIMEDOUT; } #endif /* * PUT_OOB header (first 4 bytes) in npcx 32-bits rx buffer * * [24:31] - LEN[0:7] Data length of PUT_OOB request package * [20:23] - TAG Tag of PUT_OOB * [16:19] - LEN[8:11] Data length of PUT_OOB request package * [8:15] - CYCLE_TYPE Cycle type of PUT_OOB * [0:7] - SZ_PACK Reserved. (Npcx only) */ oob_data = inst->OOBRXBUF[0]; /* Get received package length first */ sz_oob_rx = NPCX_OOB_RX_PACKAGE_LEN(oob_data); /* Check OOB received buffer size */ if (sz_oob_rx > NPCX_ESPI_OOB_MAX_PAYLOAD) { LOG_ERR("Out of OOB received buffer: %d", sz_oob_rx); return -EINVAL; } /* Set received size to package structure */ pckt->len = sz_oob_rx; /* Read PUT_OOB data into 32-bits rx buffer in little endian */ for (idx_rx_buf = 0; idx_rx_buf < sz_oob_rx/4; idx_rx_buf++) { oob_data = inst->OOBRXBUF[idx_rx_buf + 1]; *(oob_buf++) = oob_data & 0xFF; *(oob_buf++) = (oob_data >> 8) & 0xFF; *(oob_buf++) = (oob_data >> 16) & 0xFF; *(oob_buf++) = (oob_data >> 24) & 0xFF; } /* Read remaining bytes of package */ if (sz_oob_rx % 4) { int i; oob_data = inst->OOBRXBUF[idx_rx_buf + 1]; for (i = 0; i < sz_oob_rx % 4; i++) { *(oob_buf++) = (oob_data >> (8 * i)) & 0xFF; } } /* Notify host that OOB received buffer is free now. */ inst->OOBCTL |= BIT(NPCX_OOBCTL_OOB_FREE); return 0; } #endif #ifdef CONFIG_ESPI_FLASH_CHANNEL static void espi_npcx_flash_prepare_tx_header(const struct device *dev, int cyc_type, int flash_addr, int flash_len, int tx_payload) { struct espi_reg *const inst = HAL_INSTANCE(dev); /* * First 3 bytes of flash cycle command header in tx buffer * * [24:31] - LEN[0:7] = n Data length of flash cycle request * [16:23] - LEN[8:15] = 0 Ignore it since max buffer size is 64 bytes * [12:15] - TAG = 0 Tag of flash cycle command is always 0 here * [8:11] - CYCLE_TYPE = 0 Cycle type of flash command * [0:7] - SZ_PACK = 7 Overall tx package size. (Used internally.) */ inst->FLASHTXBUF[0] = (flash_len << 24) | (cyc_type << 8) | (tx_payload + ESPI_FLASH_HEADER_PCKT_SIZE); /* * Following 4 bytes of tager flash address in tx buffer * * [24:31] - ADDR[0:7] Start address of flash cycle command request * [16:23] - ADDR[15:8] * [8:15] - ADDR[23:16] * [0:7] - ADDR[31:24] */ inst->FLASHTXBUF[1] = sys_cpu_to_be32(flash_addr); } static int espi_npcx_flash_parse_completion(const struct device *dev) { int cycle_type; struct espi_reg *const inst = HAL_INSTANCE(dev); /* * First 3 bytes of flash cycle completion header in rx buffer * * [24:31] - LEN[0:7] Data length of flash cycle completion package * [16:23] - LEN[8:15] Ignore it since rx bufer size is 64 bytes * [12:15] - TAG Tag of flash cycle completion package * [8:11] - CYCLE_TYPE Cycle type of flash completion * [0:7] - Reserved */ cycle_type = (inst->FLASHRXBUF[0] & 0xff00) >> 8; if (cycle_type == ESPI_FLASH_SUCCESS_WITHOUT_DATA_CYCLE_TYPE) { return 0; } return -EIO; } static int espi_npcx_flash_parse_completion_with_data(const struct device *dev, struct espi_flash_packet *pckt) { struct espi_reg *const inst = HAL_INSTANCE(dev); int cycle_type, sz_rx_payload; /* * First 3 bytes of flash cycle completion header in rx buffer * * [24:31] - LEN[0:7] Data length of flash cycle completion package * [16:23] - LEN[8:15] Ignore it since rx bufer size is 64 bytes * [12:15] - TAG Tag of flash cycle completion package * [8:11] - CYCLE_TYPE Cycle type of flash completion * [0:7] - Reserved * * The following is flash data/ */ cycle_type = (inst->FLASHRXBUF[0] & 0xff00) >> 8; sz_rx_payload = inst->FLASHRXBUF[0] >> 24; if (cycle_type == ESPI_FLASH_SUCCESS_WITH_DATA_CYCLE_TYPE) { volatile uint32_t *rx_buf = &inst->FLASHRXBUF[1]; uint8_t *buf = pckt->buf; uint32_t data; /* Get data from flash RX buffer */ for (int i = 0; i < sz_rx_payload / 4; i++, rx_buf++) { data = *rx_buf; for (int j = 0; j < 4; j++, buf++) { *buf = data & 0xff; data = data >> 8; } } /* Get remaining bytes */ if (sz_rx_payload % 4) { data = *rx_buf; for (int j = 0; j < sz_rx_payload % 4; j++, buf++) { *buf = data & 0xff; data = data >> 8; } } return 0; } return -EIO; } static int espi_npcx_flash_read(const struct device *dev, struct espi_flash_packet *pckt) { int ret; struct espi_reg *const inst = HAL_INSTANCE(dev); struct espi_npcx_data *const data = dev->data; /* Check out of FLASH received buffer size */ if (pckt->len > NPCX_ESPI_FLASH_MAX_RX_PAYLOAD) { LOG_ERR("Out of FLASH transmitted buffer: %d", pckt->len); return -EINVAL; } /* Check Flash Transmit Queue is empty? */ if (IS_BIT_SET(inst->FLASHCTL, NPCX_FLASHCTL_FLASH_TX_AVAIL)) { LOG_ERR("flash channel is busy"); return -EBUSY; } /* Prepare FLASH_READ header in tx buffer */ espi_npcx_flash_prepare_tx_header(dev, ESPI_FLASH_READ_CYCLE_TYPE, pckt->flash_addr, pckt->len, 0); /* Set the FLASHCTL.FLASH_TX_AVAIL bit to 1 to enqueue the packet */ inst->FLASHCTL |= BIT(NPCX_FLASHCTL_FLASH_TX_AVAIL); /* Wait until get flash package or timeout */ ret = k_sem_take(&data->flash_rx_lock, K_MSEC(ESPI_FLASH_MAX_TIMEOUT)); if (ret == -EAGAIN) { LOG_ERR("%s: Timeout", __func__); return -ETIMEDOUT; } return espi_npcx_flash_parse_completion_with_data(dev, pckt); } static int espi_npcx_flash_write(const struct device *dev, struct espi_flash_packet *pckt) { int ret; uint32_t tx_data; struct espi_reg *const inst = HAL_INSTANCE(dev); struct espi_npcx_data *const data = dev->data; volatile uint32_t *tx_buf = &inst->FLASHTXBUF[2]; uint8_t *buf = pckt->buf; /* Check out of FLASH transmitted buffer size */ if (pckt->len > NPCX_ESPI_FLASH_MAX_TX_PAYLOAD) { LOG_ERR("Out of FLASH transmitted buffer: %d", pckt->len); return -EINVAL; } /* Check Flash Transmit Queue is empty? */ if (IS_BIT_SET(inst->FLASHCTL, NPCX_FLASHCTL_FLASH_TX_AVAIL)) { LOG_ERR("flash channel is busy"); return -EBUSY; } /* Prepare FLASH_WRITE header in tx buffer */ espi_npcx_flash_prepare_tx_header(dev, ESPI_FLASH_WRITE_CYCLE_TYPE, pckt->flash_addr, pckt->len, pckt->len); /* Put package data to flash TX buffer */ for (int i = 0; i < pckt->len / 4; i++, tx_buf++) { tx_data = 0; for (int j = 0; j < 4; j++, buf++) { tx_data |= (*buf << (j * 8)); } *tx_buf = tx_data; } /* Put remaining bytes to flash TX buffer */ if (pckt->len % 4) { tx_data = 0; for (int j = 0; j < pckt->len % 4; j++, buf++) { tx_data |= (*buf << (j * 8)); } *tx_buf = tx_data; } /* Set the FLASHCTL.FLASH_TX_AVAIL bit to 1 to enqueue the packet */ inst->FLASHCTL |= BIT(NPCX_FLASHCTL_FLASH_TX_AVAIL); /* Wait until get flash package or timeout */ ret = k_sem_take(&data->flash_rx_lock, K_MSEC(ESPI_FLASH_MAX_TIMEOUT)); if (ret == -EAGAIN) { LOG_ERR("%s: Timeout", __func__); return -ETIMEDOUT; } /* Parse completion package in rx buffer */ return espi_npcx_flash_parse_completion(dev); } static int espi_npcx_flash_erase(const struct device *dev, struct espi_flash_packet *pckt) { int ret; struct espi_reg *const inst = HAL_INSTANCE(dev); struct espi_npcx_data *const data = dev->data; /* Check Flash Transmit Queue is empty? */ if (IS_BIT_SET(inst->FLASHCTL, NPCX_FLASHCTL_FLASH_TX_AVAIL)) { LOG_ERR("flash channel is busy"); return -EBUSY; } /* Prepare FLASH_ERASE header in tx buffer */ espi_npcx_flash_prepare_tx_header(dev, ESPI_FLASH_ERASE_CYCLE_TYPE, pckt->flash_addr, pckt->len, 0); /* Set the FLASHCTL.FLASH_TX_AVAIL bit to 1 to enqueue the packet */ inst->FLASHCTL |= BIT(NPCX_FLASHCTL_FLASH_TX_AVAIL); /* Wait until get flash package or timeout */ ret = k_sem_take(&data->flash_rx_lock, K_MSEC(ESPI_FLASH_MAX_TIMEOUT)); if (ret == -EAGAIN) { LOG_ERR("%s: Timeout", __func__); return -ETIMEDOUT; } /* Parse completion package in rx buffer */ return espi_npcx_flash_parse_completion(dev); } #endif /* Platform specific espi module functions */ void npcx_espi_enable_interrupts(const struct device *dev) { const struct espi_npcx_config *const config = dev->config; /* Enable eSPI bus interrupt */ irq_enable(DT_INST_IRQN(0)); /* Turn on all VW inputs' MIWU interrupts */ for (int idx = 0; idx < ARRAY_SIZE(vw_in_tbl); idx++) { npcx_miwu_irq_enable(&(vw_in_tbl[idx].vw_wui)); } npcx_miwu_irq_enable(&config->espi_rst_wui); } void npcx_espi_disable_interrupts(const struct device *dev) { const struct espi_npcx_config *const config = dev->config; /* Disable eSPI bus interrupt */ irq_disable(DT_INST_IRQN(0)); /* Turn off all VW inputs' MIWU interrupts */ for (int idx = 0; idx < ARRAY_SIZE(vw_in_tbl); idx++) { npcx_miwu_irq_disable(&(vw_in_tbl[idx].vw_wui)); } npcx_miwu_irq_disable(&config->espi_rst_wui); } /* eSPI driver registration */ static int espi_npcx_init(const struct device *dev); static const struct espi_driver_api espi_npcx_driver_api = { .config = espi_npcx_configure, .get_channel_status = espi_npcx_channel_ready, .send_vwire = espi_npcx_send_vwire, .receive_vwire = espi_npcx_receive_vwire, .manage_callback = espi_npcx_manage_callback, .read_lpc_request = espi_npcx_read_lpc_request, .write_lpc_request = espi_npcx_write_lpc_request, #if defined(CONFIG_ESPI_OOB_CHANNEL) .send_oob = espi_npcx_send_oob, .receive_oob = espi_npcx_receive_oob, #endif #ifdef CONFIG_ESPI_FLASH_CHANNEL .flash_read = espi_npcx_flash_read, .flash_write = espi_npcx_flash_write, .flash_erase = espi_npcx_flash_erase, #endif }; static struct espi_npcx_data espi_npcx_data; PINCTRL_DT_INST_DEFINE(0); BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "only one 'nuvoton_npcx_espi' compatible node may be present"); static const struct espi_npcx_config espi_npcx_config = { .base = DT_INST_REG_ADDR(0), .espi_rst_wui = NPCX_DT_WUI_ITEM_BY_NAME(0, espi_rst_wui), .clk_cfg = NPCX_DT_CLK_CFG_ITEM(0), .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), }; DEVICE_DT_INST_DEFINE(0, &espi_npcx_init, NULL, &espi_npcx_data, &espi_npcx_config, PRE_KERNEL_2, CONFIG_ESPI_INIT_PRIORITY, &espi_npcx_driver_api); static int espi_npcx_init(const struct device *dev) { const struct espi_npcx_config *const config = dev->config; struct espi_npcx_data *const data = dev->data; struct espi_reg *const inst = HAL_INSTANCE(dev); const struct device *const clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE); int i, ret; if (!device_is_ready(clk_dev)) { LOG_ERR("clock control device not ready"); return -ENODEV; } /* Turn on eSPI device clock first */ ret = clock_control_on(clk_dev, (clock_control_subsys_t) &config->clk_cfg); if (ret < 0) { LOG_ERR("Turn on eSPI clock fail %d", ret); return ret; } if (IS_ENABLED(CONFIG_ESPI_NPCX_BYPASS_CH_ENABLE_FATAL_ERROR)) { /* Enable the access to the NPCX_ONLY_ESPI_REG2 register */ inst->NPCX_ONLY_ESPI_REG1 = NPCX_ONLY_ESPI_REG1_UNLOCK_REG2; inst->NPCX_ONLY_ESPI_REG2 &= ~BIT(NPCX_ONLY_ESPI_REG2_TRANS_END_CONFIG); /* Disable the access to the NPCX_ONLY_ESPI_REG2 register */ inst->NPCX_ONLY_ESPI_REG1 = NPCX_ONLY_ESPI_REG1_LOCK_REG2; } /* Enable events which share the same espi bus interrupt */ for (i = 0; i < ARRAY_SIZE(espi_bus_isr_tbl); i++) { inst->ESPIIE |= BIT(espi_bus_isr_tbl[i].int_en_bit); inst->ESPIWE |= BIT(espi_bus_isr_tbl[i].wake_en_bit); } #if !defined(CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC) k_sem_init(&data->oob_rx_lock, 0, 1); #endif #if defined(CONFIG_ESPI_FLASH_CHANNEL) k_sem_init(&data->flash_rx_lock, 0, 1); #endif /* Configure Virtual Wire input signals */ for (i = 0; i < ARRAY_SIZE(vw_in_tbl); i++) { espi_vw_config_input(dev, &vw_in_tbl[i]); } /* Configure Virtual Wire output signals */ for (i = 0; i < ARRAY_SIZE(vw_out_tbl); i++) { espi_vw_config_output(dev, &vw_out_tbl[i]); } /* Configure Virtual Wire GPIOs that are output high at reset state */ for (i = 0; i < ARRAY_SIZE(vw_out_gpio_tbl1); i++) { espi_vw_gpio_config_output(dev, &vw_out_gpio_tbl1[i], 1); } /* Configure wake-up input and callback for eSPI VW input signal */ for (i = 0; i < ARRAY_SIZE(vw_in_tbl); i++) { espi_init_wui_callback(dev, &vw_in_callback[i], &vw_in_tbl[i].vw_wui, espi_vw_generic_isr); } /* Configure wake-up input and callback for ESPI_RST signal */ espi_init_wui_callback(dev, &espi_rst_callback, &config->espi_rst_wui, espi_vw_espi_rst_isr); #if DT_NODE_HAS_PROP(DT_DRV_INST(0), vw_index_extend_set) uint8_t vw_ex_len = ARRAY_SIZE(espi_npcx_vw_ex_0); uint8_t dir, num, index; for (i = 0; i < vw_ex_len; i++) { dir = espi_npcx_vw_ex_0[i].direction; num = espi_npcx_vw_ex_0[i].group_num; index = espi_npcx_vw_ex_0[i].index; if (dir == ESPI_CONTROLLER_TO_TARGET) { if (num >= NPCX_VWEVMS_MAX) { LOG_ERR("Error Setting for VW extend MS group (%x)", num); return -EINVAL; } SET_FIELD(inst->VWEVMS[num], NPCX_VWEVMS_INDEX, index); SET_FIELD(inst->VWEVMS[num], NPCX_VWEVMS_VALID, 0x0); inst->VWEVMS[num] |= BIT(NPCX_VWEVMS_INDEX_EN); } else if (dir == ESPI_TARGET_TO_CONTROLLER) { if (num >= NPCX_VWEVSM_MAX) { LOG_ERR("Error Setting for VW extend SM group (%x)", num); return -EINVAL; } SET_FIELD(inst->VWEVSM[num], NPCX_VWEVSM_INDEX, index); SET_FIELD(inst->VWEVSM[num], NPCX_VWEVSM_VALID, 0x0); inst->VWEVSM[num] |= BIT(NPCX_VWEVSM_INDEX_EN); } else { LOG_ERR("Error Setting for VW extend direction (%x)", dir); return -EINVAL; } } #endif /* Configure pin-mux for eSPI bus device */ ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); if (ret < 0) { LOG_ERR("eSPI pinctrl setup failed (%d)", ret); return ret; } /* Configure host sub-modules which HW blocks belong to core domain */ npcx_host_init_subs_core_domain(dev, &data->callbacks); #if defined(CONFIG_ESPI_FLASH_CHANNEL) && defined(CONFIG_ESPI_TAF) npcx_init_taf(dev, &data->callbacks); #endif /* eSPI Bus interrupt installation */ IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), espi_bus_generic_isr, DEVICE_DT_INST_GET(0), 0); /* Enable eSPI bus interrupt */ irq_enable(DT_INST_IRQN(0)); return 0; }