| /* |
| * Copyright (c) 2019 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #define DT_DRV_COMPAT microchip_xec_espi |
| |
| #include <zephyr/kernel.h> |
| #include <soc.h> |
| #include <errno.h> |
| #include <zephyr/drivers/espi.h> |
| #include <zephyr/drivers/pinctrl.h> |
| #include <zephyr/logging/log.h> |
| #include <zephyr/irq.h> |
| #include "espi_utils.h" |
| |
| /* Minimum delay before acknowledging a virtual wire */ |
| #define ESPI_XEC_VWIRE_ACK_DELAY 10ul |
| |
| /* Maximum timeout to transmit a virtual wire packet. |
| * 10 ms expressed in multiples of 100us |
| */ |
| #define ESPI_XEC_VWIRE_SEND_TIMEOUT 100ul |
| |
| #define VW_MAX_GIRQS 2ul |
| |
| /* 200ms */ |
| #define MAX_OOB_TIMEOUT 200ul |
| /* 1s */ |
| #define MAX_FLASH_TIMEOUT 1000ul |
| |
| /* While issuing flash erase command, it should be ensured that the transfer |
| * length specified is non-zero. |
| */ |
| #define ESPI_FLASH_ERASE_DUMMY 0x01ul |
| |
| /* OOB maximum address configuration */ |
| #define ESPI_XEC_OOB_ADDR_MSW 0x1FFFul |
| #define ESPI_XEC_OOB_ADDR_LSW 0xFFFFul |
| |
| /* OOB Rx length */ |
| #define ESPI_XEC_OOB_RX_LEN 0x7F00ul |
| |
| /* BARs as defined in LPC spec chapter 11 */ |
| #define ESPI_XEC_KBC_BAR_ADDRESS 0x00600000 |
| #define ESPI_XEC_UART0_BAR_ADDRESS 0x03F80000 |
| #define ESPI_XEC_MBOX_BAR_ADDRESS 0x03600000 |
| #define ESPI_XEC_PORT80_BAR_ADDRESS 0x00800000 |
| #define ESPI_XEC_PORT81_BAR_ADDRESS 0x00810000 |
| |
| /* Espi peripheral has 3 uart ports */ |
| #define ESPI_PERIPHERAL_UART_PORT0 0 |
| #define ESPI_PERIPHERAL_UART_PORT1 1 |
| #define ESPI_PERIPHERAL_UART_PORT2 2 |
| |
| #define UART_DEFAULT_IRQ_POS 2u |
| #define UART_DEFAULT_IRQ BIT(UART_DEFAULT_IRQ_POS) |
| |
| /* VM index 0x50 for OCB */ |
| #define ESPI_OCB_VW_INDEX 0x50u |
| |
| LOG_MODULE_REGISTER(espi, CONFIG_ESPI_LOG_LEVEL); |
| |
| struct espi_isr { |
| uint32_t girq_bit; |
| void (*the_isr)(const struct device *dev); |
| }; |
| |
| struct espi_xec_config { |
| uint32_t base_addr; |
| uint8_t bus_girq_id; |
| uint8_t vw_girq_ids[VW_MAX_GIRQS]; |
| uint8_t pc_girq_id; |
| const struct pinctrl_dev_config *pcfg; |
| }; |
| |
| struct espi_xec_data { |
| sys_slist_t callbacks; |
| struct k_sem tx_lock; |
| struct k_sem rx_lock; |
| struct k_sem flash_lock; |
| }; |
| |
| struct xec_signal { |
| uint8_t xec_reg_idx; |
| uint8_t bit; |
| uint8_t dir; |
| }; |
| |
| enum mchp_msvw_regs { |
| MCHP_MSVW00, |
| MCHP_MSVW01, |
| MCHP_MSVW02, |
| MCHP_MSVW03, |
| MCHP_MSVW04, |
| MCHP_MSVW05, |
| MCHP_MSVW06, |
| MCHP_MSVW07, |
| MCHP_MSVW08, |
| }; |
| |
| enum mchp_smvw_regs { |
| MCHP_SMVW00, |
| MCHP_SMVW01, |
| MCHP_SMVW02, |
| MCHP_SMVW03, |
| MCHP_SMVW04, |
| MCHP_SMVW05, |
| MCHP_SMVW06, |
| MCHP_SMVW07, |
| MCHP_SMVW08, |
| }; |
| |
| /* Microchip canonical virtual wire mapping |
| * --------------------------------------------------------------------------------| |
| * VW Idx | VW reg | SRC_ID3 | SRC_ID2 | SRC_ID1 | SRC_ID0 | |
| * --------------------------------------------------------------------------------| |
| * System Event Virtual Wires |
| * --------------------------------------------------------------------------------| |
| * 2h | MSVW00 | res | SLP_S5# | SLP_S4# | SLP_S3# | |
| * 3h | MSVW01 | res | OOB_RST_WARN | PLTRST# | SUS_STAT# | |
| * 4h | SMVW00 | PME# | WAKE# | res | OOB_RST_ACK | |
| * 5h | SMVW01 | TARGET_BOOT_STS | ERR_NONFATAL | ERR_FATAL | TARGET_BOOT_DONE | |
| * 6h | SMVW02 | HOST_RST_ACK | RCIN# | SMI# | SCI# | |
| * 7h | MSVW02 | res | res | res | HOS_RST_WARN | |
| * --------------------------------------------------------------------------------| |
| * Platform specific virtual wires |
| * --------------------------------------------------------------------------------| |
| * 40h | SMVW03 | res | res | DNX_ACK | SUS_ACK# | |
| * 41h | MSVW03 | SLP_A# | res | SUS_PDNACK| SUS_WARN# | |
| * 42h | MSVW04 | res | res | SLP_WLAN# | SLP_LAN# | |
| * 43h | MSVW05 | generic | generic | generic | generic | |
| * 44h | MSVW06 | generic | generic | generic | generic | |
| * 45h | SMVW04 | generic | generic | generic | generic | |
| * 46h | SMVW05 | generic | generic | generic | generic | |
| * 47h | MSVW07 | res | res | res | HOST_C10 | |
| * 4Ah | MSVW08 | res | res | DNX_WARN | res | |
| * 50h | SMVW06 | ESPI_OCB_3 | ESPI_OCB_2 | ESPI_OCB_1| ESPI_OCB_0 | |
| */ |
| |
| static const struct xec_signal vw_tbl[] = { |
| /* MSVW00 */ |
| [ESPI_VWIRE_SIGNAL_SLP_S3] = {MCHP_MSVW00, ESPI_VWIRE_SRC_ID0, |
| ESPI_CONTROLLER_TO_TARGET}, |
| [ESPI_VWIRE_SIGNAL_SLP_S4] = {MCHP_MSVW00, ESPI_VWIRE_SRC_ID1, |
| ESPI_CONTROLLER_TO_TARGET}, |
| [ESPI_VWIRE_SIGNAL_SLP_S5] = {MCHP_MSVW00, ESPI_VWIRE_SRC_ID2, |
| ESPI_CONTROLLER_TO_TARGET}, |
| /* MSVW01 */ |
| [ESPI_VWIRE_SIGNAL_SUS_STAT] = {MCHP_MSVW01, ESPI_VWIRE_SRC_ID0, |
| ESPI_CONTROLLER_TO_TARGET}, |
| [ESPI_VWIRE_SIGNAL_PLTRST] = {MCHP_MSVW01, ESPI_VWIRE_SRC_ID1, |
| ESPI_CONTROLLER_TO_TARGET}, |
| [ESPI_VWIRE_SIGNAL_OOB_RST_WARN] = {MCHP_MSVW01, ESPI_VWIRE_SRC_ID2, |
| ESPI_CONTROLLER_TO_TARGET}, |
| /* SMVW00 */ |
| [ESPI_VWIRE_SIGNAL_OOB_RST_ACK] = {MCHP_SMVW00, ESPI_VWIRE_SRC_ID0, |
| ESPI_TARGET_TO_CONTROLLER}, |
| [ESPI_VWIRE_SIGNAL_WAKE] = {MCHP_SMVW00, ESPI_VWIRE_SRC_ID2, |
| ESPI_TARGET_TO_CONTROLLER}, |
| [ESPI_VWIRE_SIGNAL_PME] = {MCHP_SMVW00, ESPI_VWIRE_SRC_ID3, |
| ESPI_TARGET_TO_CONTROLLER}, |
| /* SMVW01 */ |
| [ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE] = {MCHP_SMVW01, ESPI_VWIRE_SRC_ID0, |
| ESPI_TARGET_TO_CONTROLLER}, |
| [ESPI_VWIRE_SIGNAL_ERR_FATAL] = {MCHP_SMVW01, ESPI_VWIRE_SRC_ID1, |
| ESPI_TARGET_TO_CONTROLLER}, |
| [ESPI_VWIRE_SIGNAL_ERR_NON_FATAL] = {MCHP_SMVW01, ESPI_VWIRE_SRC_ID2, |
| ESPI_TARGET_TO_CONTROLLER}, |
| [ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS] = {MCHP_SMVW01, ESPI_VWIRE_SRC_ID3, |
| ESPI_TARGET_TO_CONTROLLER}, |
| /* SMVW02 */ |
| [ESPI_VWIRE_SIGNAL_SCI] = {MCHP_SMVW02, ESPI_VWIRE_SRC_ID0, |
| ESPI_TARGET_TO_CONTROLLER}, |
| [ESPI_VWIRE_SIGNAL_SMI] = {MCHP_SMVW02, ESPI_VWIRE_SRC_ID1, |
| ESPI_TARGET_TO_CONTROLLER}, |
| [ESPI_VWIRE_SIGNAL_RST_CPU_INIT] = {MCHP_SMVW02, ESPI_VWIRE_SRC_ID2, |
| ESPI_TARGET_TO_CONTROLLER}, |
| [ESPI_VWIRE_SIGNAL_HOST_RST_ACK] = {MCHP_SMVW02, ESPI_VWIRE_SRC_ID3, |
| ESPI_TARGET_TO_CONTROLLER}, |
| /* MSVW02 */ |
| [ESPI_VWIRE_SIGNAL_HOST_RST_WARN] = {MCHP_MSVW02, ESPI_VWIRE_SRC_ID0, |
| ESPI_CONTROLLER_TO_TARGET}, |
| /* SMVW03 */ |
| [ESPI_VWIRE_SIGNAL_SUS_ACK] = {MCHP_SMVW03, ESPI_VWIRE_SRC_ID0, |
| ESPI_TARGET_TO_CONTROLLER}, |
| [ESPI_VWIRE_SIGNAL_DNX_ACK] = {MCHP_SMVW03, ESPI_VWIRE_SRC_ID1, |
| ESPI_TARGET_TO_CONTROLLER}, |
| /* MSVW03 */ |
| [ESPI_VWIRE_SIGNAL_SUS_WARN] = {MCHP_MSVW03, ESPI_VWIRE_SRC_ID0, |
| ESPI_CONTROLLER_TO_TARGET}, |
| [ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK] = {MCHP_MSVW03, ESPI_VWIRE_SRC_ID1, |
| ESPI_CONTROLLER_TO_TARGET}, |
| [ESPI_VWIRE_SIGNAL_SLP_A] = {MCHP_MSVW03, ESPI_VWIRE_SRC_ID3, |
| ESPI_CONTROLLER_TO_TARGET}, |
| /* MSVW04 */ |
| [ESPI_VWIRE_SIGNAL_SLP_LAN] = {MCHP_MSVW04, ESPI_VWIRE_SRC_ID0, |
| ESPI_CONTROLLER_TO_TARGET}, |
| [ESPI_VWIRE_SIGNAL_SLP_WLAN] = {MCHP_MSVW04, ESPI_VWIRE_SRC_ID1, |
| ESPI_CONTROLLER_TO_TARGET}, |
| /* MSVW07 */ |
| [ESPI_VWIRE_SIGNAL_HOST_C10] = {MCHP_MSVW07, ESPI_VWIRE_SRC_ID0, |
| ESPI_CONTROLLER_TO_TARGET}, |
| /* MSVW08 */ |
| [ESPI_VWIRE_SIGNAL_DNX_WARN] = {MCHP_MSVW08, ESPI_VWIRE_SRC_ID1, |
| ESPI_CONTROLLER_TO_TARGET}, |
| /* SMVW06 */ |
| [ESPI_VWIRE_SIGNAL_OCB_0] = {MCHP_SMVW06, ESPI_VWIRE_SRC_ID0, |
| ESPI_TARGET_TO_CONTROLLER}, |
| [ESPI_VWIRE_SIGNAL_OCB_1] = {MCHP_SMVW06, ESPI_VWIRE_SRC_ID1, |
| ESPI_TARGET_TO_CONTROLLER}, |
| [ESPI_VWIRE_SIGNAL_OCB_2] = {MCHP_SMVW06, ESPI_VWIRE_SRC_ID2, |
| ESPI_TARGET_TO_CONTROLLER}, |
| [ESPI_VWIRE_SIGNAL_OCB_3] = {MCHP_SMVW06, ESPI_VWIRE_SRC_ID3, |
| ESPI_TARGET_TO_CONTROLLER}, |
| }; |
| |
| /* Buffer size are expressed in bytes */ |
| #ifdef CONFIG_ESPI_OOB_CHANNEL |
| static uint32_t target_rx_mem[CONFIG_ESPI_OOB_BUFFER_SIZE >> 2]; |
| static uint32_t target_tx_mem[CONFIG_ESPI_OOB_BUFFER_SIZE >> 2]; |
| #endif |
| #ifdef CONFIG_ESPI_FLASH_CHANNEL |
| static uint32_t target_mem[CONFIG_ESPI_FLASH_BUFFER_SIZE >> 2]; |
| #endif |
| |
| static int espi_xec_configure(const struct device *dev, struct espi_cfg *cfg) |
| { |
| uint8_t iomode = 0; |
| uint8_t cap0 = ESPI_CAP_REGS->GLB_CAP0; |
| uint8_t cap1 = ESPI_CAP_REGS->GLB_CAP1; |
| uint8_t cur_iomode = (cap1 & MCHP_ESPI_GBL_CAP1_IO_MODE_MASK) >> |
| MCHP_ESPI_GBL_CAP1_IO_MODE_POS; |
| |
| /* Set frequency */ |
| cap1 &= ~MCHP_ESPI_GBL_CAP1_MAX_FREQ_MASK; |
| |
| switch (cfg->max_freq) { |
| case 20: |
| cap1 |= MCHP_ESPI_GBL_CAP1_MAX_FREQ_20M; |
| break; |
| case 25: |
| cap1 |= MCHP_ESPI_GBL_CAP1_MAX_FREQ_25M; |
| break; |
| case 33: |
| cap1 |= MCHP_ESPI_GBL_CAP1_MAX_FREQ_33M; |
| break; |
| case 50: |
| cap1 |= MCHP_ESPI_GBL_CAP1_MAX_FREQ_50M; |
| break; |
| case 66: |
| cap1 |= MCHP_ESPI_GBL_CAP1_MAX_FREQ_66M; |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| /* Set IO mode */ |
| iomode = (cfg->io_caps >> 1); |
| if (iomode > 3) { |
| return -EINVAL; |
| } |
| |
| if (iomode != cur_iomode) { |
| cap1 &= ~(MCHP_ESPI_GBL_CAP1_IO_MODE_MASK0 << |
| MCHP_ESPI_GBL_CAP1_IO_MODE_POS); |
| cap1 |= (iomode << MCHP_ESPI_GBL_CAP1_IO_MODE_POS); |
| } |
| |
| /* Validate and translate eSPI API channels to MEC capabilities */ |
| cap0 &= ~MCHP_ESPI_GBL_CAP0_MASK; |
| if (cfg->channel_caps & ESPI_CHANNEL_PERIPHERAL) { |
| if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_CHANNEL)) { |
| cap0 |= MCHP_ESPI_GBL_CAP0_PC_SUPP; |
| } else { |
| return -EINVAL; |
| } |
| } |
| |
| if (cfg->channel_caps & ESPI_CHANNEL_VWIRE) { |
| if (IS_ENABLED(CONFIG_ESPI_VWIRE_CHANNEL)) { |
| cap0 |= MCHP_ESPI_GBL_CAP0_VW_SUPP; |
| } else { |
| return -EINVAL; |
| } |
| } |
| |
| if (cfg->channel_caps & ESPI_CHANNEL_OOB) { |
| if (IS_ENABLED(CONFIG_ESPI_OOB_CHANNEL)) { |
| cap0 |= MCHP_ESPI_GBL_CAP0_OOB_SUPP; |
| } else { |
| return -EINVAL; |
| } |
| } |
| |
| if (cfg->channel_caps & ESPI_CHANNEL_FLASH) { |
| if (IS_ENABLED(CONFIG_ESPI_FLASH_CHANNEL)) { |
| cap0 |= MCHP_ESPI_GBL_CAP0_FC_SUPP; |
| } else { |
| LOG_ERR("Flash channel not supported"); |
| return -EINVAL; |
| } |
| } |
| |
| ESPI_CAP_REGS->GLB_CAP0 = cap0; |
| ESPI_CAP_REGS->GLB_CAP1 = cap1; |
| |
| /* Activate the eSPI block *. |
| * Need to guarantee that this register is configured before RSMRST# |
| * de-assertion and after pinmux |
| */ |
| ESPI_EIO_BAR_REGS->IO_ACTV = 1; |
| LOG_DBG("eSPI block activated successfully"); |
| |
| return 0; |
| } |
| |
| static bool espi_xec_channel_ready(const struct device *dev, |
| enum espi_channel ch) |
| { |
| bool sts; |
| |
| switch (ch) { |
| case ESPI_CHANNEL_PERIPHERAL: |
| sts = ESPI_CAP_REGS->PC_RDY & MCHP_ESPI_PC_READY; |
| break; |
| case ESPI_CHANNEL_VWIRE: |
| sts = ESPI_CAP_REGS->VW_RDY & MCHP_ESPI_VW_READY; |
| break; |
| case ESPI_CHANNEL_OOB: |
| sts = ESPI_CAP_REGS->OOB_RDY & MCHP_ESPI_OOB_READY; |
| break; |
| case ESPI_CHANNEL_FLASH: |
| sts = ESPI_CAP_REGS->FC_RDY & MCHP_ESPI_FC_READY; |
| break; |
| default: |
| sts = false; |
| break; |
| } |
| |
| return sts; |
| } |
| |
| static int espi_xec_read_lpc_request(const struct device *dev, |
| enum lpc_peripheral_opcode op, |
| uint32_t *data) |
| { |
| ARG_UNUSED(dev); |
| |
| if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) { |
| /* Make sure kbc 8042 is on */ |
| if (!(KBC_REGS->KBC_CTRL & MCHP_KBC_CTRL_OBFEN)) { |
| return -ENOTSUP; |
| } |
| |
| switch (op) { |
| case E8042_OBF_HAS_CHAR: |
| /* EC has written data back to host. OBF is |
| * automatically cleared after host reads |
| * the data |
| */ |
| *data = KBC_REGS->EC_KBC_STS & MCHP_KBC_STS_OBF ? 1 : 0; |
| break; |
| case E8042_IBF_HAS_CHAR: |
| *data = KBC_REGS->EC_KBC_STS & MCHP_KBC_STS_IBF ? 1 : 0; |
| break; |
| case E8042_READ_KB_STS: |
| *data = KBC_REGS->EC_KBC_STS; |
| break; |
| default: |
| return -EINVAL; |
| } |
| } else { |
| return -ENOTSUP; |
| } |
| |
| return 0; |
| } |
| |
| static int espi_xec_write_lpc_request(const struct device *dev, |
| enum lpc_peripheral_opcode op, |
| uint32_t *data) |
| { |
| struct espi_xec_config *config = |
| (struct espi_xec_config *) (dev->config); |
| |
| volatile uint32_t __attribute__((unused)) dummy; |
| |
| if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) { |
| /* Make sure kbc 8042 is on */ |
| if (!(KBC_REGS->KBC_CTRL & MCHP_KBC_CTRL_OBFEN)) { |
| return -ENOTSUP; |
| } |
| |
| switch (op) { |
| case E8042_WRITE_KB_CHAR: |
| KBC_REGS->EC_DATA = *data & 0xff; |
| break; |
| case E8042_WRITE_MB_CHAR: |
| KBC_REGS->EC_AUX_DATA = *data & 0xff; |
| break; |
| case E8042_RESUME_IRQ: |
| MCHP_GIRQ_SRC(config->pc_girq_id) = MCHP_KBC_IBF_GIRQ; |
| MCHP_GIRQ_ENSET(config->pc_girq_id) = MCHP_KBC_IBF_GIRQ; |
| break; |
| case E8042_PAUSE_IRQ: |
| MCHP_GIRQ_ENCLR(config->pc_girq_id) = MCHP_KBC_IBF_GIRQ; |
| break; |
| case E8042_CLEAR_OBF: |
| dummy = KBC_REGS->HOST_AUX_DATA; |
| break; |
| case E8042_SET_FLAG: |
| /* FW shouldn't modify these flags directly */ |
| *data &= ~(MCHP_KBC_STS_OBF | MCHP_KBC_STS_IBF | |
| MCHP_KBC_STS_AUXOBF); |
| KBC_REGS->EC_KBC_STS |= *data; |
| break; |
| case E8042_CLEAR_FLAG: |
| /* FW shouldn't modify these flags directly */ |
| *data |= (MCHP_KBC_STS_OBF | MCHP_KBC_STS_IBF | |
| MCHP_KBC_STS_AUXOBF); |
| KBC_REGS->EC_KBC_STS &= ~(*data); |
| break; |
| default: |
| return -EINVAL; |
| } |
| } else { |
| return -ENOTSUP; |
| |
| } |
| |
| return 0; |
| } |
| |
| static int espi_xec_send_vwire(const struct device *dev, |
| enum espi_vwire_signal signal, uint8_t level) |
| { |
| struct xec_signal signal_info = vw_tbl[signal]; |
| uint8_t xec_id = signal_info.xec_reg_idx; |
| uint8_t src_id = signal_info.bit; |
| |
| if ((src_id >= ESPI_VWIRE_SRC_ID_MAX) || |
| (xec_id >= ESPI_MSVW_IDX_MAX)) { |
| return -EINVAL; |
| } |
| |
| if (signal_info.dir == ESPI_CONTROLLER_TO_TARGET) { |
| ESPI_MSVW_REG *reg = &(ESPI_M2S_VW_REGS->MSVW00) + xec_id; |
| uint8_t *p8 = (uint8_t *)®->SRC; |
| |
| *(p8 + (uintptr_t) src_id) = level; |
| } |
| |
| if (signal_info.dir == ESPI_TARGET_TO_CONTROLLER) { |
| ESPI_SMVW_REG *reg = &(ESPI_S2M_VW_REGS->SMVW00) + xec_id; |
| uint8_t *p8 = (uint8_t *)®->SRC; |
| |
| *(p8 + (uintptr_t) src_id) = level; |
| |
| /* Ensure eSPI virtual wire packet is transmitted |
| * There is no interrupt, so need to poll register |
| */ |
| uint8_t rd_cnt = ESPI_XEC_VWIRE_SEND_TIMEOUT; |
| |
| while (reg->SRC_CHG && rd_cnt--) { |
| k_busy_wait(100); |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int espi_xec_receive_vwire(const struct device *dev, |
| enum espi_vwire_signal signal, uint8_t *level) |
| { |
| struct xec_signal signal_info = vw_tbl[signal]; |
| uint8_t xec_id = signal_info.xec_reg_idx; |
| uint8_t src_id = signal_info.bit; |
| |
| if ((src_id >= ESPI_VWIRE_SRC_ID_MAX) || |
| (xec_id >= ESPI_SMVW_IDX_MAX) || (level == NULL)) { |
| return -EINVAL; |
| } |
| |
| if (signal_info.dir == ESPI_CONTROLLER_TO_TARGET) { |
| ESPI_MSVW_REG *reg = &(ESPI_M2S_VW_REGS->MSVW00) + xec_id; |
| *level = ((reg->SRC >> (src_id << 3)) & 0x01ul); |
| } |
| |
| if (signal_info.dir == ESPI_TARGET_TO_CONTROLLER) { |
| ESPI_SMVW_REG *reg = &(ESPI_S2M_VW_REGS->SMVW00) + xec_id; |
| *level = ((reg->SRC >> (src_id << 3)) & 0x01ul); |
| } |
| |
| return 0; |
| } |
| |
| #ifdef CONFIG_ESPI_OOB_CHANNEL |
| static int espi_xec_send_oob(const struct device *dev, |
| struct espi_oob_packet *pckt) |
| { |
| int ret; |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| uint8_t err_mask = MCHP_ESPI_OOB_TX_STS_IBERR | |
| MCHP_ESPI_OOB_TX_STS_OVRUN | |
| MCHP_ESPI_OOB_TX_STS_BADREQ; |
| |
| LOG_DBG("%s", __func__); |
| |
| if (!(ESPI_OOB_REGS->TX_STS & MCHP_ESPI_OOB_TX_STS_CHEN)) { |
| LOG_ERR("OOB channel is disabled"); |
| return -EIO; |
| } |
| |
| if (ESPI_OOB_REGS->TX_STS & MCHP_ESPI_OOB_TX_STS_BUSY) { |
| LOG_ERR("OOB channel is busy"); |
| return -EBUSY; |
| } |
| |
| if (pckt->len > CONFIG_ESPI_OOB_BUFFER_SIZE) { |
| LOG_ERR("insufficient space"); |
| return -EINVAL; |
| } |
| |
| memcpy(target_tx_mem, pckt->buf, pckt->len); |
| |
| ESPI_OOB_REGS->TX_LEN = pckt->len; |
| ESPI_OOB_REGS->TX_CTRL = MCHP_ESPI_OOB_TX_CTRL_START; |
| LOG_DBG("%s %d", __func__, ESPI_OOB_REGS->TX_LEN); |
| |
| /* Wait until ISR or timeout */ |
| ret = k_sem_take(&data->tx_lock, K_MSEC(MAX_OOB_TIMEOUT)); |
| if (ret == -EAGAIN) { |
| return -ETIMEDOUT; |
| } |
| |
| if (ESPI_OOB_REGS->TX_STS & err_mask) { |
| LOG_ERR("Tx failed %x", ESPI_OOB_REGS->TX_STS); |
| ESPI_OOB_REGS->TX_STS = err_mask; |
| return -EIO; |
| } |
| |
| return 0; |
| } |
| |
| static int espi_xec_receive_oob(const struct device *dev, |
| struct espi_oob_packet *pckt) |
| { |
| uint8_t err_mask = MCHP_ESPI_OOB_RX_STS_IBERR | |
| MCHP_ESPI_OOB_RX_STS_OVRUN; |
| |
| if (ESPI_OOB_REGS->TX_STS & err_mask) { |
| return -EIO; |
| } |
| |
| #ifndef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC |
| int ret; |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| |
| /* Wait until ISR or timeout */ |
| ret = k_sem_take(&data->rx_lock, K_MSEC(MAX_OOB_TIMEOUT)); |
| if (ret == -EAGAIN) { |
| return -ETIMEDOUT; |
| } |
| #endif |
| /* Check if buffer passed to driver can fit the received buffer */ |
| uint32_t rcvd_len = ESPI_OOB_REGS->RX_LEN & MCHP_ESPI_OOB_RX_LEN_MASK; |
| |
| if (rcvd_len > pckt->len) { |
| LOG_ERR("space rcvd %d vs %d", rcvd_len, pckt->len); |
| return -EIO; |
| } |
| |
| pckt->len = rcvd_len; |
| memcpy(pckt->buf, target_rx_mem, pckt->len); |
| memset(target_rx_mem, 0, pckt->len); |
| |
| /* Only after data has been copied from SRAM, indicate channel |
| * is available for next packet |
| */ |
| ESPI_OOB_REGS->RX_CTRL |= MCHP_ESPI_OOB_RX_CTRL_AVAIL; |
| |
| return 0; |
| } |
| #endif /* CONFIG_ESPI_OOB_CHANNEL */ |
| |
| #ifdef CONFIG_ESPI_FLASH_CHANNEL |
| static int espi_xec_flash_read(const struct device *dev, |
| struct espi_flash_packet *pckt) |
| { |
| int ret; |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| uint32_t err_mask = MCHP_ESPI_FC_STS_IBERR | |
| MCHP_ESPI_FC_STS_FAIL | |
| MCHP_ESPI_FC_STS_OVFL | |
| MCHP_ESPI_FC_STS_BADREQ; |
| |
| LOG_DBG("%s", __func__); |
| |
| if (!(ESPI_FC_REGS->STS & MCHP_ESPI_FC_STS_CHAN_EN)) { |
| LOG_ERR("Flash channel is disabled"); |
| return -EIO; |
| } |
| |
| if (pckt->len > CONFIG_ESPI_FLASH_BUFFER_SIZE) { |
| LOG_ERR("Invalid size request"); |
| return -EINVAL; |
| } |
| |
| ESPI_FC_REGS->FL_ADDR_MSW = 0; |
| ESPI_FC_REGS->FL_ADDR_LSW = pckt->flash_addr; |
| ESPI_FC_REGS->MEM_ADDR_MSW = 0; |
| ESPI_FC_REGS->MEM_ADDR_LSW = (uint32_t)&target_mem[0]; |
| ESPI_FC_REGS->XFR_LEN = pckt->len; |
| ESPI_FC_REGS->CTRL = MCHP_ESPI_FC_CTRL_FUNC(MCHP_ESPI_FC_CTRL_RD0); |
| ESPI_FC_REGS->CTRL |= MCHP_ESPI_FC_CTRL_START; |
| |
| /* Wait until ISR or timeout */ |
| ret = k_sem_take(&data->flash_lock, K_MSEC(MAX_FLASH_TIMEOUT)); |
| if (ret == -EAGAIN) { |
| LOG_ERR("%s timeout", __func__); |
| return -ETIMEDOUT; |
| } |
| |
| if (ESPI_FC_REGS->STS & err_mask) { |
| LOG_ERR("%s error %x", __func__, err_mask); |
| ESPI_FC_REGS->STS = err_mask; |
| return -EIO; |
| } |
| |
| memcpy(pckt->buf, target_mem, pckt->len); |
| |
| return 0; |
| } |
| |
| static int espi_xec_flash_write(const struct device *dev, |
| struct espi_flash_packet *pckt) |
| { |
| int ret; |
| uint32_t err_mask = MCHP_ESPI_FC_STS_IBERR | |
| MCHP_ESPI_FC_STS_OVRUN | |
| MCHP_ESPI_FC_STS_FAIL | |
| MCHP_ESPI_FC_STS_BADREQ; |
| |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| |
| LOG_DBG("%s", __func__); |
| |
| if (sizeof(target_mem) < pckt->len) { |
| LOG_ERR("Packet length is too big"); |
| return -ENOMEM; |
| } |
| |
| if (!(ESPI_FC_REGS->STS & MCHP_ESPI_FC_STS_CHAN_EN)) { |
| LOG_ERR("Flash channel is disabled"); |
| return -EIO; |
| } |
| |
| if ((ESPI_FC_REGS->CFG & MCHP_ESPI_FC_CFG_BUSY)) { |
| LOG_ERR("Flash channel is busy"); |
| return -EBUSY; |
| } |
| |
| memcpy(target_mem, pckt->buf, pckt->len); |
| |
| ESPI_FC_REGS->FL_ADDR_MSW = 0; |
| ESPI_FC_REGS->FL_ADDR_LSW = pckt->flash_addr; |
| ESPI_FC_REGS->MEM_ADDR_MSW = 0; |
| ESPI_FC_REGS->MEM_ADDR_LSW = (uint32_t)&target_mem[0]; |
| ESPI_FC_REGS->XFR_LEN = pckt->len; |
| ESPI_FC_REGS->CTRL = MCHP_ESPI_FC_CTRL_FUNC(MCHP_ESPI_FC_CTRL_WR0); |
| ESPI_FC_REGS->CTRL |= MCHP_ESPI_FC_CTRL_START; |
| |
| /* Wait until ISR or timeout */ |
| ret = k_sem_take(&data->flash_lock, K_MSEC(MAX_FLASH_TIMEOUT)); |
| if (ret == -EAGAIN) { |
| LOG_ERR("%s timeout", __func__); |
| return -ETIMEDOUT; |
| } |
| |
| if (ESPI_FC_REGS->STS & err_mask) { |
| LOG_ERR("%s err: %x", __func__, err_mask); |
| ESPI_FC_REGS->STS = err_mask; |
| return -EIO; |
| } |
| |
| return 0; |
| } |
| |
| static int espi_xec_flash_erase(const struct device *dev, |
| struct espi_flash_packet *pckt) |
| { |
| int ret; |
| uint32_t status; |
| uint32_t err_mask = MCHP_ESPI_FC_STS_IBERR | |
| MCHP_ESPI_FC_STS_OVRUN | |
| MCHP_ESPI_FC_STS_FAIL | |
| MCHP_ESPI_FC_STS_BADREQ; |
| |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| |
| LOG_DBG("%s", __func__); |
| |
| if (!(ESPI_FC_REGS->STS & MCHP_ESPI_FC_STS_CHAN_EN)) { |
| LOG_ERR("Flash channel is disabled"); |
| return -EIO; |
| } |
| |
| if ((ESPI_FC_REGS->CFG & MCHP_ESPI_FC_CFG_BUSY)) { |
| LOG_ERR("Flash channel is busy"); |
| return -EBUSY; |
| } |
| |
| /* Clear status register */ |
| status = ESPI_FC_REGS->STS; |
| ESPI_FC_REGS->STS = status; |
| |
| ESPI_FC_REGS->FL_ADDR_MSW = 0; |
| ESPI_FC_REGS->FL_ADDR_LSW = pckt->flash_addr; |
| ESPI_FC_REGS->XFR_LEN = ESPI_FLASH_ERASE_DUMMY; |
| ESPI_FC_REGS->CTRL = MCHP_ESPI_FC_CTRL_FUNC(MCHP_ESPI_FC_CTRL_ERS0); |
| ESPI_FC_REGS->CTRL |= MCHP_ESPI_FC_CTRL_START; |
| |
| /* Wait until ISR or timeout */ |
| ret = k_sem_take(&data->flash_lock, K_MSEC(MAX_FLASH_TIMEOUT)); |
| if (ret == -EAGAIN) { |
| LOG_ERR("%s timeout", __func__); |
| return -ETIMEDOUT; |
| } |
| |
| if (ESPI_FC_REGS->STS & err_mask) { |
| LOG_ERR("%s err: %x", __func__, err_mask); |
| ESPI_FC_REGS->STS = err_mask; |
| return -EIO; |
| } |
| |
| return 0; |
| } |
| #endif /* CONFIG_ESPI_FLASH_CHANNEL */ |
| |
| static int espi_xec_manage_callback(const struct device *dev, |
| struct espi_callback *callback, bool set) |
| { |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| |
| return espi_manage_callback(&data->callbacks, callback, set); |
| } |
| |
| #ifdef CONFIG_ESPI_AUTOMATIC_BOOT_DONE_ACKNOWLEDGE |
| static void send_target_bootdone(const struct device *dev) |
| { |
| int ret; |
| uint8_t boot_done; |
| |
| ret = espi_xec_receive_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, |
| &boot_done); |
| if (!ret && !boot_done) { |
| /* TARGET_BOOT_DONE & TARGET_LOAD_STS have to be sent together */ |
| espi_xec_send_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, 1); |
| espi_xec_send_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, 1); |
| } |
| } |
| #endif |
| |
| #ifdef CONFIG_ESPI_OOB_CHANNEL |
| static void espi_init_oob(const struct device *dev) |
| { |
| struct espi_xec_config *config = |
| (struct espi_xec_config *) (dev->config); |
| |
| /* Enable OOB Tx/Rx interrupts */ |
| MCHP_GIRQ_ENSET(config->bus_girq_id) = (MCHP_ESPI_OOB_UP_GIRQ_VAL | |
| MCHP_ESPI_OOB_DN_GIRQ_VAL); |
| |
| ESPI_OOB_REGS->TX_ADDR_MSW = 0; |
| ESPI_OOB_REGS->RX_ADDR_MSW = 0; |
| ESPI_OOB_REGS->TX_ADDR_LSW = (uint32_t)&target_tx_mem[0]; |
| ESPI_OOB_REGS->RX_ADDR_LSW = (uint32_t)&target_rx_mem[0]; |
| ESPI_OOB_REGS->RX_LEN = 0x00FF0000; |
| |
| /* Enable OOB Tx channel enable change status interrupt */ |
| ESPI_OOB_REGS->TX_IEN |= MCHP_ESPI_OOB_TX_IEN_CHG_EN | |
| MCHP_ESPI_OOB_TX_IEN_DONE; |
| |
| /* Enable Rx channel to receive data any time |
| * there are case where OOB is not initiated by a previous OOB Tx |
| */ |
| ESPI_OOB_REGS->RX_IEN |= MCHP_ESPI_OOB_RX_IEN; |
| ESPI_OOB_REGS->RX_CTRL |= MCHP_ESPI_OOB_RX_CTRL_AVAIL; |
| } |
| #endif |
| |
| #ifdef CONFIG_ESPI_FLASH_CHANNEL |
| static void espi_init_flash(const struct device *dev) |
| { |
| struct espi_xec_config *config = |
| (struct espi_xec_config *)(dev->config); |
| |
| LOG_DBG("%s", __func__); |
| |
| /* Need to clear status done when ROM boots in MAF */ |
| LOG_DBG("%s ESPI_FC_REGS->CFG %X", __func__, ESPI_FC_REGS->CFG); |
| ESPI_FC_REGS->STS = MCHP_ESPI_FC_STS_DONE; |
| |
| /* Enable interrupts */ |
| MCHP_GIRQ_ENSET(config->bus_girq_id) = BIT(MCHP_ESPI_FC_GIRQ_POS); |
| ESPI_FC_REGS->IEN |= MCHP_ESPI_FC_IEN_CHG_EN; |
| ESPI_FC_REGS->IEN |= MCHP_ESPI_FC_IEN_DONE; |
| } |
| #endif |
| |
| static void espi_bus_init(const struct device *dev) |
| { |
| const struct espi_xec_config *config = dev->config; |
| |
| /* Enable bus interrupts */ |
| MCHP_GIRQ_ENSET(config->bus_girq_id) = MCHP_ESPI_ESPI_RST_GIRQ_VAL | |
| MCHP_ESPI_VW_EN_GIRQ_VAL | MCHP_ESPI_PC_GIRQ_VAL; |
| } |
| |
| void espi_config_vw_ocb(void) |
| { |
| ESPI_SMVW_REG *reg = &(ESPI_S2M_VW_REGS->SMVW06); |
| |
| /* Keep index bits [7:0] in initial 0h value (disabled state) */ |
| mec_espi_smvw_index_set(reg, 0); |
| /* Set 01b (eSPI_RESET# domain) into bits [9:8] which frees the |
| * register from all except chip level resets and set initial state |
| * of VW wires as 1111b in bits [15:12]. |
| */ |
| mec_espi_msvw_stom_set(reg, VW_RST_SRC_ESPI_RESET, 0x1); |
| /* Set 4 SMVW SRC bits in bit positions [0], [8], [16] and [24] to |
| * initial value '1'. |
| */ |
| mec_espi_smvw_set_all_bitmap(reg, 0xF); |
| /* Set 00b (eSPI_RESET# domain) into bits [9:8] while preserving |
| * the values in bits [15:12]. |
| */ |
| mec_espi_msvw_stom_set(reg, VW_RST_SRC_ESPI_RESET, 0x0); |
| /* Set INDEX field with OCB VW index */ |
| mec_espi_smvw_index_set(reg, ESPI_OCB_VW_INDEX); |
| } |
| |
| static void espi_rst_isr(const struct device *dev) |
| { |
| uint8_t rst_sts; |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| struct espi_event evt = { ESPI_BUS_RESET, 0, 0 }; |
| |
| rst_sts = ESPI_CAP_REGS->ERST_STS; |
| |
| /* eSPI reset status register is clear on write register */ |
| ESPI_CAP_REGS->ERST_STS = MCHP_ESPI_RST_ISTS; |
| |
| if (rst_sts & MCHP_ESPI_RST_ISTS) { |
| if (rst_sts & MCHP_ESPI_RST_ISTS_PIN_RO_HI) { |
| evt.evt_data = 1; |
| } else { |
| evt.evt_data = 0; |
| } |
| |
| espi_send_callbacks(&data->callbacks, dev, evt); |
| #ifdef CONFIG_ESPI_OOB_CHANNEL |
| espi_init_oob(dev); |
| #endif |
| #ifdef CONFIG_ESPI_FLASH_CHANNEL |
| espi_init_flash(dev); |
| #endif |
| espi_bus_init(dev); |
| } |
| } |
| |
| /* Configure sub devices BAR address if not using default I/O based address |
| * then make its BAR valid. |
| * Refer to microchip eSPI I/O base addresses for default values |
| */ |
| static void config_sub_devices(const struct device *dev) |
| { |
| #ifdef CONFIG_ESPI_PERIPHERAL_UART |
| /* eSPI logical UART is tied to corresponding physical UART |
| * Not all boards use same UART port for debug, hence needs to set |
| * eSPI host logical UART0 bar address based on configuration. |
| */ |
| switch (CONFIG_ESPI_PERIPHERAL_UART_SOC_MAPPING) { |
| case 0: |
| ESPI_EIO_BAR_REGS->EC_BAR_UART_0 = ESPI_XEC_UART0_BAR_ADDRESS | |
| MCHP_ESPI_IO_BAR_HOST_VALID; |
| break; |
| case 1: |
| ESPI_EIO_BAR_REGS->EC_BAR_UART_1 = ESPI_XEC_UART0_BAR_ADDRESS | |
| MCHP_ESPI_IO_BAR_HOST_VALID; |
| break; |
| case 2: |
| ESPI_EIO_BAR_REGS->EC_BAR_UART_2 = ESPI_XEC_UART0_BAR_ADDRESS | |
| MCHP_ESPI_IO_BAR_HOST_VALID; |
| break; |
| } |
| #endif |
| #ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC |
| KBC_REGS->KBC_CTRL |= MCHP_KBC_CTRL_AUXH; |
| KBC_REGS->KBC_CTRL |= MCHP_KBC_CTRL_OBFEN; |
| /* This is the activate register, but the HAL has a funny name */ |
| KBC_REGS->KBC_PORT92_EN = MCHP_KBC_PORT92_EN; |
| ESPI_EIO_BAR_REGS->EC_BAR_KBC = ESPI_XEC_KBC_BAR_ADDRESS | |
| MCHP_ESPI_IO_BAR_HOST_VALID; |
| #endif |
| #ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO |
| ESPI_EIO_BAR_REGS->EC_BAR_ACPI_EC_0 |= MCHP_ESPI_IO_BAR_HOST_VALID; |
| ESPI_EIO_BAR_REGS->EC_BAR_MBOX = ESPI_XEC_MBOX_BAR_ADDRESS | |
| MCHP_ESPI_IO_BAR_HOST_VALID; |
| #endif |
| #ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT |
| ESPI_EIO_BAR_REGS->EC_BAR_ACPI_EC_1 = |
| CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT_PORT_NUM | |
| MCHP_ESPI_IO_BAR_HOST_VALID; |
| ESPI_EIO_BAR_REGS->EC_BAR_MBOX = ESPI_XEC_MBOX_BAR_ADDRESS | |
| MCHP_ESPI_IO_BAR_HOST_VALID; |
| #endif |
| |
| #ifdef CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80 |
| ESPI_EIO_BAR_REGS->EC_BAR_P80CAP_0 = ESPI_XEC_PORT80_BAR_ADDRESS | |
| MCHP_ESPI_IO_BAR_HOST_VALID; |
| PORT80_CAP0_REGS->ACTV = 1; |
| ESPI_EIO_BAR_REGS->EC_BAR_P80CAP_1 = ESPI_XEC_PORT81_BAR_ADDRESS | |
| MCHP_ESPI_IO_BAR_HOST_VALID; |
| PORT80_CAP1_REGS->ACTV = 1; |
| #endif |
| } |
| |
| static void configure_sirq(void) |
| { |
| #ifdef CONFIG_ESPI_PERIPHERAL_UART |
| switch (CONFIG_ESPI_PERIPHERAL_UART_SOC_MAPPING) { |
| case ESPI_PERIPHERAL_UART_PORT0: |
| ESPI_SIRQ_REGS->UART_0_SIRQ = UART_DEFAULT_IRQ; |
| break; |
| case ESPI_PERIPHERAL_UART_PORT1: |
| ESPI_SIRQ_REGS->UART_1_SIRQ = UART_DEFAULT_IRQ; |
| break; |
| case ESPI_PERIPHERAL_UART_PORT2: |
| ESPI_SIRQ_REGS->UART_2_SIRQ = UART_DEFAULT_IRQ; |
| break; |
| } |
| #endif |
| #ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC |
| ESPI_SIRQ_REGS->KBC_SIRQ_0 = 0x01; |
| ESPI_SIRQ_REGS->KBC_SIRQ_1 = 0x0C; |
| #endif |
| } |
| |
| static void setup_espi_io_config(const struct device *dev, |
| uint16_t host_address) |
| { |
| ESPI_EIO_BAR_REGS->EC_BAR_IOC = (host_address << 16) | |
| MCHP_ESPI_IO_BAR_HOST_VALID; |
| |
| config_sub_devices(dev); |
| configure_sirq(); |
| |
| ESPI_PC_REGS->PC_STATUS = (MCHP_ESPI_PC_STS_EN_CHG | |
| MCHP_ESPI_PC_STS_BM_EN_CHG_POS); |
| ESPI_PC_REGS->PC_IEN |= MCHP_ESPI_PC_IEN_EN_CHG; |
| ESPI_CAP_REGS->PC_RDY = 1; |
| } |
| |
| static void espi_pc_isr(const struct device *dev) |
| { |
| uint32_t status = ESPI_PC_REGS->PC_STATUS; |
| |
| if (status & MCHP_ESPI_PC_STS_EN_CHG) { |
| if (status & MCHP_ESPI_PC_STS_EN) { |
| setup_espi_io_config(dev, MCHP_ESPI_IOBAR_INIT_DFLT); |
| } |
| |
| ESPI_PC_REGS->PC_STATUS = MCHP_ESPI_PC_STS_EN_CHG; |
| } |
| } |
| |
| static void espi_vwire_chanel_isr(const struct device *dev) |
| { |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| const struct espi_xec_config *config = dev->config; |
| struct espi_event evt = { .evt_type = ESPI_BUS_EVENT_CHANNEL_READY, |
| .evt_details = ESPI_CHANNEL_VWIRE, |
| .evt_data = 0 }; |
| uint32_t status; |
| |
| status = ESPI_IO_VW_REGS->VW_EN_STS; |
| |
| if (status & MCHP_ESPI_VW_EN_STS_RO) { |
| ESPI_IO_VW_REGS->VW_RDY = 1; |
| evt.evt_data = 1; |
| /* VW channel interrupt can disabled at this point */ |
| MCHP_GIRQ_ENCLR(config->bus_girq_id) = MCHP_ESPI_VW_EN_GIRQ_VAL; |
| #ifdef CONFIG_ESPI_AUTOMATIC_BOOT_DONE_ACKNOWLEDGE |
| send_target_bootdone(dev); |
| #endif |
| } |
| |
| espi_send_callbacks(&data->callbacks, dev, evt); |
| } |
| |
| #ifdef CONFIG_ESPI_OOB_CHANNEL |
| static void espi_oob_down_isr(const struct device *dev) |
| { |
| uint32_t status; |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| #ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC |
| struct espi_event evt = { .evt_type = ESPI_BUS_EVENT_OOB_RECEIVED, |
| .evt_details = 0, |
| .evt_data = 0 }; |
| #endif |
| |
| status = ESPI_OOB_REGS->RX_STS; |
| |
| LOG_DBG("%s %x", __func__, status); |
| if (status & MCHP_ESPI_OOB_RX_STS_DONE) { |
| /* Register is write-on-clear, ensure only 1 bit is affected */ |
| ESPI_OOB_REGS->RX_STS = MCHP_ESPI_OOB_RX_STS_DONE; |
| |
| #ifndef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC |
| k_sem_give(&data->rx_lock); |
| #else |
| evt.evt_details = ESPI_OOB_REGS->RX_LEN & MCHP_ESPI_OOB_RX_LEN_MASK; |
| espi_send_callbacks(&data->callbacks, dev, evt); |
| #endif |
| } |
| } |
| |
| static void espi_oob_up_isr(const struct device *dev) |
| { |
| uint32_t status; |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| struct espi_event evt = { .evt_type = ESPI_BUS_EVENT_CHANNEL_READY, |
| .evt_details = ESPI_CHANNEL_OOB, |
| .evt_data = 0 |
| }; |
| |
| status = ESPI_OOB_REGS->TX_STS; |
| LOG_DBG("%s sts:%x", __func__, status); |
| |
| if (status & MCHP_ESPI_OOB_TX_STS_DONE) { |
| /* Register is write-on-clear, ensure only 1 bit is affected */ |
| ESPI_OOB_REGS->TX_STS = MCHP_ESPI_OOB_TX_STS_DONE; |
| k_sem_give(&data->tx_lock); |
| } |
| |
| if (status & MCHP_ESPI_OOB_TX_STS_CHG_EN) { |
| if (status & MCHP_ESPI_OOB_TX_STS_CHEN) { |
| espi_init_oob(dev); |
| /* Indicate OOB channel is ready to eSPI host */ |
| ESPI_CAP_REGS->OOB_RDY = 1; |
| evt.evt_data = 1; |
| } |
| |
| ESPI_OOB_REGS->TX_STS = MCHP_ESPI_OOB_TX_STS_CHG_EN; |
| espi_send_callbacks(&data->callbacks, dev, evt); |
| } |
| } |
| #endif |
| |
| #ifdef CONFIG_ESPI_FLASH_CHANNEL |
| static void espi_flash_isr(const struct device *dev) |
| { |
| uint32_t status; |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| struct espi_event evt = { .evt_type = ESPI_BUS_EVENT_CHANNEL_READY, |
| .evt_details = ESPI_CHANNEL_FLASH, |
| .evt_data = 0, |
| }; |
| |
| status = ESPI_FC_REGS->STS; |
| LOG_DBG("%s %x", __func__, status); |
| |
| if (status & MCHP_ESPI_FC_STS_DONE) { |
| /* Ensure to clear only relevant bit */ |
| ESPI_FC_REGS->STS = MCHP_ESPI_FC_STS_DONE; |
| |
| k_sem_give(&data->flash_lock); |
| } |
| |
| if (status & MCHP_ESPI_FC_STS_CHAN_EN_CHG) { |
| /* Ensure to clear only relevant bit */ |
| ESPI_FC_REGS->STS = MCHP_ESPI_FC_STS_CHAN_EN_CHG; |
| |
| if (status & MCHP_ESPI_FC_STS_CHAN_EN) { |
| espi_init_flash(dev); |
| /* Indicate flash channel is ready to eSPI controller */ |
| ESPI_CAP_REGS->FC_RDY = MCHP_ESPI_FC_READY; |
| evt.evt_data = 1; |
| } |
| |
| espi_send_callbacks(&data->callbacks, dev, evt); |
| } |
| } |
| #endif |
| |
| static void vw_pltrst_isr(const struct device *dev) |
| { |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| struct espi_event evt = { ESPI_BUS_EVENT_VWIRE_RECEIVED, |
| ESPI_VWIRE_SIGNAL_PLTRST, 0 |
| }; |
| uint8_t status = 0; |
| |
| espi_xec_receive_vwire(dev, ESPI_VWIRE_SIGNAL_PLTRST, &status); |
| if (status) { |
| setup_espi_io_config(dev, MCHP_ESPI_IOBAR_INIT_DFLT); |
| } |
| |
| evt.evt_data = status; |
| espi_send_callbacks(&data->callbacks, dev, evt); |
| } |
| |
| /* Send callbacks if enabled and track eSPI host system state */ |
| static void notify_system_state(const struct device *dev, |
| enum espi_vwire_signal signal) |
| { |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| struct espi_event evt = { ESPI_BUS_EVENT_VWIRE_RECEIVED, 0, 0 }; |
| uint8_t status = 0; |
| |
| espi_xec_receive_vwire(dev, signal, &status); |
| evt.evt_details = signal; |
| evt.evt_data = status; |
| espi_send_callbacks(&data->callbacks, dev, evt); |
| } |
| |
| static void notify_host_warning(const struct device *dev, |
| enum espi_vwire_signal signal) |
| { |
| uint8_t status; |
| |
| espi_xec_receive_vwire(dev, signal, &status); |
| |
| if (!IS_ENABLED(CONFIG_ESPI_AUTOMATIC_WARNING_ACKNOWLEDGE)) { |
| struct espi_xec_data *data = |
| (struct espi_xec_data *)(dev->data); |
| struct espi_event evt = {ESPI_BUS_EVENT_VWIRE_RECEIVED, 0, 0 }; |
| |
| evt.evt_details = signal; |
| evt.evt_data = status; |
| espi_send_callbacks(&data->callbacks, dev, evt); |
| } else { |
| k_busy_wait(ESPI_XEC_VWIRE_ACK_DELAY); |
| /* Some flows are dependent on awareness of client's driver |
| * about these warnings in such cases these automatic response |
| * should not be enabled. |
| */ |
| switch (signal) { |
| case ESPI_VWIRE_SIGNAL_HOST_RST_WARN: |
| espi_xec_send_vwire(dev, |
| ESPI_VWIRE_SIGNAL_HOST_RST_ACK, |
| status); |
| break; |
| case ESPI_VWIRE_SIGNAL_SUS_WARN: |
| espi_xec_send_vwire(dev, ESPI_VWIRE_SIGNAL_SUS_ACK, |
| status); |
| break; |
| case ESPI_VWIRE_SIGNAL_OOB_RST_WARN: |
| espi_xec_send_vwire(dev, ESPI_VWIRE_SIGNAL_OOB_RST_ACK, |
| status); |
| break; |
| case ESPI_VWIRE_SIGNAL_DNX_WARN: |
| espi_xec_send_vwire(dev, ESPI_VWIRE_SIGNAL_DNX_ACK, |
| status); |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| static void vw_slp3_isr(const struct device *dev) |
| { |
| notify_system_state(dev, ESPI_VWIRE_SIGNAL_SLP_S3); |
| } |
| |
| static void vw_slp4_isr(const struct device *dev) |
| { |
| notify_system_state(dev, ESPI_VWIRE_SIGNAL_SLP_S4); |
| } |
| |
| static void vw_slp5_isr(const struct device *dev) |
| { |
| notify_system_state(dev, ESPI_VWIRE_SIGNAL_SLP_S5); |
| } |
| |
| static void vw_host_rst_warn_isr(const struct device *dev) |
| { |
| notify_host_warning(dev, ESPI_VWIRE_SIGNAL_HOST_RST_WARN); |
| } |
| |
| static void vw_sus_warn_isr(const struct device *dev) |
| { |
| notify_host_warning(dev, ESPI_VWIRE_SIGNAL_SUS_WARN); |
| /* Configure spare VW register SMVW06 to VW index 50h. As per |
| * per microchip recommendation, spare VW register should be |
| * configured between TARGET_BOOT_LOAD_DONE = 1 VW event and |
| * point where SUS_ACK=1 VW is sent to SOC. |
| */ |
| espi_config_vw_ocb(); |
| } |
| |
| static void vw_oob_rst_isr(const struct device *dev) |
| { |
| notify_host_warning(dev, ESPI_VWIRE_SIGNAL_OOB_RST_WARN); |
| } |
| |
| static void vw_sus_pwrdn_ack_isr(const struct device *dev) |
| { |
| notify_system_state(dev, ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK); |
| } |
| |
| static void vw_sus_slp_a_isr(const struct device *dev) |
| { |
| notify_system_state(dev, ESPI_VWIRE_SIGNAL_SLP_A); |
| } |
| |
| static void ibf_isr(const struct device *dev) |
| { |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| struct espi_event evt = { ESPI_BUS_PERIPHERAL_NOTIFICATION, |
| ESPI_PERIPHERAL_HOST_IO, ESPI_PERIPHERAL_NODATA |
| }; |
| |
| espi_send_callbacks(&data->callbacks, dev, evt); |
| } |
| |
| #ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT |
| static void ibf_pvt_isr(const struct device *dev) |
| { |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| struct espi_event evt = { |
| .evt_type = ESPI_BUS_PERIPHERAL_NOTIFICATION, |
| .evt_details = ESPI_PERIPHERAL_HOST_IO_PVT, |
| .evt_data = ESPI_PERIPHERAL_NODATA |
| }; |
| |
| espi_send_callbacks(&data->callbacks, dev, evt); |
| } |
| #endif |
| |
| static void ibf_kbc_isr(const struct device *dev) |
| { |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| |
| /* The high byte contains information from the host, |
| * and the lower byte specifies if the host sent |
| * a command or data. 1 = Command. |
| */ |
| uint32_t isr_data = ((KBC_REGS->EC_DATA & 0xFF) << E8042_ISR_DATA_POS) | |
| ((KBC_REGS->EC_KBC_STS & MCHP_KBC_STS_CD) << |
| E8042_ISR_CMD_DATA_POS); |
| |
| struct espi_event evt = { |
| .evt_type = ESPI_BUS_PERIPHERAL_NOTIFICATION, |
| .evt_details = ESPI_PERIPHERAL_8042_KBC, |
| .evt_data = isr_data |
| }; |
| |
| espi_send_callbacks(&data->callbacks, dev, evt); |
| } |
| |
| static void port80_isr(const struct device *dev) |
| { |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| struct espi_event evt = { ESPI_BUS_PERIPHERAL_NOTIFICATION, |
| (ESPI_PERIPHERAL_INDEX_0 << 16) | ESPI_PERIPHERAL_DEBUG_PORT80, |
| ESPI_PERIPHERAL_NODATA |
| }; |
| |
| evt.evt_data = PORT80_CAP0_REGS->EC_DATA; |
| espi_send_callbacks(&data->callbacks, dev, evt); |
| } |
| |
| static void port81_isr(const struct device *dev) |
| { |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| struct espi_event evt = { ESPI_BUS_PERIPHERAL_NOTIFICATION, |
| (ESPI_PERIPHERAL_INDEX_1 << 16) | ESPI_PERIPHERAL_DEBUG_PORT80, |
| ESPI_PERIPHERAL_NODATA |
| }; |
| |
| evt.evt_data = PORT80_CAP1_REGS->EC_DATA; |
| espi_send_callbacks(&data->callbacks, dev, evt); |
| } |
| |
| const struct espi_isr espi_bus_isr[] = { |
| {MCHP_ESPI_PC_GIRQ_VAL, espi_pc_isr}, |
| #ifdef CONFIG_ESPI_OOB_CHANNEL |
| {MCHP_ESPI_OOB_UP_GIRQ_VAL, espi_oob_up_isr}, |
| {MCHP_ESPI_OOB_DN_GIRQ_VAL, espi_oob_down_isr}, |
| #endif |
| #ifdef CONFIG_ESPI_FLASH_CHANNEL |
| {MCHP_ESPI_FC_GIRQ_VAL, espi_flash_isr}, |
| #endif |
| {MCHP_ESPI_ESPI_RST_GIRQ_VAL, espi_rst_isr}, |
| {MCHP_ESPI_VW_EN_GIRQ_VAL, espi_vwire_chanel_isr}, |
| }; |
| |
| uint8_t vw_wires_int_en[] = { |
| ESPI_VWIRE_SIGNAL_SLP_S3, |
| ESPI_VWIRE_SIGNAL_SLP_S4, |
| ESPI_VWIRE_SIGNAL_SLP_S5, |
| ESPI_VWIRE_SIGNAL_PLTRST, |
| ESPI_VWIRE_SIGNAL_OOB_RST_WARN, |
| ESPI_VWIRE_SIGNAL_HOST_RST_WARN, |
| ESPI_VWIRE_SIGNAL_SUS_WARN, |
| ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK, |
| ESPI_VWIRE_SIGNAL_DNX_WARN, |
| }; |
| |
| const struct espi_isr m2s_vwires_isr[] = { |
| {MEC_ESPI_MSVW00_SRC0_VAL, vw_slp3_isr}, |
| {MEC_ESPI_MSVW00_SRC1_VAL, vw_slp4_isr}, |
| {MEC_ESPI_MSVW00_SRC2_VAL, vw_slp5_isr}, |
| {MEC_ESPI_MSVW01_SRC1_VAL, vw_pltrst_isr}, |
| {MEC_ESPI_MSVW01_SRC2_VAL, vw_oob_rst_isr}, |
| {MEC_ESPI_MSVW02_SRC0_VAL, vw_host_rst_warn_isr}, |
| {MEC_ESPI_MSVW03_SRC0_VAL, vw_sus_warn_isr}, |
| {MEC_ESPI_MSVW03_SRC1_VAL, vw_sus_pwrdn_ack_isr}, |
| {MEC_ESPI_MSVW03_SRC3_VAL, vw_sus_slp_a_isr}, |
| }; |
| |
| const struct espi_isr peripherals_isr[] = { |
| {MCHP_ACPI_EC_0_IBF_GIRQ, ibf_isr}, |
| #ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT |
| {MCHP_ACPI_EC_1_IBF_GIRQ, ibf_pvt_isr}, |
| #endif |
| {MCHP_KBC_IBF_GIRQ, ibf_kbc_isr}, |
| {MCHP_PORT80_DEBUG0_GIRQ_VAL, port80_isr}, |
| {MCHP_PORT80_DEBUG1_GIRQ_VAL, port81_isr}, |
| }; |
| |
| static uint8_t bus_isr_cnt = sizeof(espi_bus_isr) / sizeof(struct espi_isr); |
| static uint8_t m2s_vwires_isr_cnt = |
| sizeof(m2s_vwires_isr) / sizeof(struct espi_isr); |
| static uint8_t periph_isr_cnt = sizeof(peripherals_isr) / sizeof(struct espi_isr); |
| |
| static void espi_xec_bus_isr(const struct device *dev) |
| { |
| const struct espi_xec_config *config = dev->config; |
| uint32_t girq_result; |
| |
| girq_result = MCHP_GIRQ_RESULT(config->bus_girq_id); |
| |
| for (int i = 0; i < bus_isr_cnt; i++) { |
| struct espi_isr entry = espi_bus_isr[i]; |
| |
| if (girq_result & entry.girq_bit) { |
| if (entry.the_isr != NULL) { |
| entry.the_isr(dev); |
| } |
| } |
| } |
| |
| REG32(MCHP_GIRQ_SRC_ADDR(config->bus_girq_id)) = girq_result; |
| } |
| |
| static void espi_xec_vw_isr(const struct device *dev) |
| { |
| const struct espi_xec_config *config = dev->config; |
| uint32_t girq_result; |
| |
| girq_result = MCHP_GIRQ_RESULT(config->vw_girq_ids[0]); |
| MCHP_GIRQ_SRC(config->vw_girq_ids[0]) = girq_result; |
| |
| for (int i = 0; i < m2s_vwires_isr_cnt; i++) { |
| struct espi_isr entry = m2s_vwires_isr[i]; |
| |
| if (girq_result & entry.girq_bit) { |
| if (entry.the_isr != NULL) { |
| entry.the_isr(dev); |
| } |
| } |
| } |
| } |
| |
| #if DT_INST_PROP_HAS_IDX(0, vw_girqs, 1) |
| static void vw_sus_dnx_warn_isr(const struct device *dev) |
| { |
| notify_host_warning(dev, ESPI_VWIRE_SIGNAL_DNX_WARN); |
| } |
| |
| const struct espi_isr m2s_vwires_ext_isr[] = { |
| {MEC_ESPI_MSVW08_SRC1_VAL, vw_sus_dnx_warn_isr} |
| }; |
| |
| static void espi_xec_vw_ext_isr(const struct device *dev) |
| { |
| const struct espi_xec_config *config = dev->config; |
| uint32_t girq_result; |
| |
| girq_result = MCHP_GIRQ_RESULT(config->vw_girq_ids[1]); |
| MCHP_GIRQ_SRC(config->vw_girq_ids[1]) = girq_result; |
| |
| for (int i = 0; i < ARRAY_SIZE(m2s_vwires_ext_isr); i++) { |
| struct espi_isr entry = m2s_vwires_ext_isr[i]; |
| |
| if (girq_result & entry.girq_bit) { |
| if (entry.the_isr != NULL) { |
| entry.the_isr(dev); |
| } |
| } |
| } |
| } |
| #endif |
| |
| static void espi_xec_periph_isr(const struct device *dev) |
| { |
| const struct espi_xec_config *config = dev->config; |
| uint32_t girq_result; |
| |
| girq_result = MCHP_GIRQ_RESULT(config->pc_girq_id); |
| |
| for (int i = 0; i < periph_isr_cnt; i++) { |
| struct espi_isr entry = peripherals_isr[i]; |
| |
| if (girq_result & entry.girq_bit) { |
| if (entry.the_isr != NULL) { |
| entry.the_isr(dev); |
| } |
| } |
| } |
| |
| REG32(MCHP_GIRQ_SRC_ADDR(config->pc_girq_id)) = girq_result; |
| } |
| |
| static int espi_xec_init(const struct device *dev); |
| |
| static const struct espi_driver_api espi_xec_driver_api = { |
| .config = espi_xec_configure, |
| .get_channel_status = espi_xec_channel_ready, |
| .send_vwire = espi_xec_send_vwire, |
| .receive_vwire = espi_xec_receive_vwire, |
| #ifdef CONFIG_ESPI_OOB_CHANNEL |
| .send_oob = espi_xec_send_oob, |
| .receive_oob = espi_xec_receive_oob, |
| #endif |
| #ifdef CONFIG_ESPI_FLASH_CHANNEL |
| .flash_read = espi_xec_flash_read, |
| .flash_write = espi_xec_flash_write, |
| .flash_erase = espi_xec_flash_erase, |
| #endif |
| .manage_callback = espi_xec_manage_callback, |
| .read_lpc_request = espi_xec_read_lpc_request, |
| .write_lpc_request = espi_xec_write_lpc_request, |
| }; |
| |
| static struct espi_xec_data espi_xec_data; |
| |
| /* pin control structure(s) */ |
| PINCTRL_DT_INST_DEFINE(0); |
| |
| static const struct espi_xec_config espi_xec_config = { |
| .base_addr = DT_INST_REG_ADDR(0), |
| .bus_girq_id = DT_INST_PROP(0, io_girq), |
| .vw_girq_ids[0] = DT_INST_PROP_BY_IDX(0, vw_girqs, 0), |
| .vw_girq_ids[1] = DT_INST_PROP_BY_IDX(0, vw_girqs, 1), |
| .pc_girq_id = DT_INST_PROP(0, pc_girq), |
| .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), |
| }; |
| |
| DEVICE_DT_INST_DEFINE(0, &espi_xec_init, NULL, |
| &espi_xec_data, &espi_xec_config, |
| PRE_KERNEL_2, CONFIG_ESPI_INIT_PRIORITY, |
| &espi_xec_driver_api); |
| |
| static int espi_xec_init(const struct device *dev) |
| { |
| const struct espi_xec_config *config = dev->config; |
| struct espi_xec_data *data = (struct espi_xec_data *)(dev->data); |
| int ret; |
| |
| ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); |
| if (ret != 0) { |
| LOG_ERR("XEC eSPI pinctrl setup failed (%d)", ret); |
| return ret; |
| } |
| |
| /* Configure eSPI_PLTRST# to cause nSIO_RESET reset */ |
| PCR_REGS->PWR_RST_CTRL = MCHP_PCR_PR_CTRL_USE_ESPI_PLTRST; |
| ESPI_CAP_REGS->PLTRST_SRC = MCHP_ESPI_PLTRST_SRC_IS_VW; |
| |
| /* Configure the channels and its capabilities based on build config */ |
| ESPI_CAP_REGS->GLB_CAP0 |= MCHP_ESPI_GBL_CAP0_VW_SUPP; |
| ESPI_CAP_REGS->GLB_CAP0 |= MCHP_ESPI_GBL_CAP0_PC_SUPP; |
| |
| /* Max VW count is 12 pairs */ |
| ESPI_CAP_REGS->VW_CAP = ESPI_NUM_SMVW; |
| ESPI_CAP_REGS->PC_CAP |= MCHP_ESPI_PC_CAP_MAX_PLD_SZ_64; |
| |
| #ifdef CONFIG_ESPI_OOB_CHANNEL |
| ESPI_CAP_REGS->GLB_CAP0 |= MCHP_ESPI_GBL_CAP0_OOB_SUPP; |
| ESPI_CAP_REGS->OOB_CAP |= MCHP_ESPI_OOB_CAP_MAX_PLD_SZ_73; |
| |
| k_sem_init(&data->tx_lock, 0, 1); |
| #ifndef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC |
| k_sem_init(&data->rx_lock, 0, 1); |
| #endif /* CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC */ |
| #else |
| ESPI_CAP_REGS->GLB_CAP0 &= ~MCHP_ESPI_GBL_CAP0_OOB_SUPP; |
| #endif |
| |
| #ifdef CONFIG_ESPI_FLASH_CHANNEL |
| ESPI_CAP_REGS->GLB_CAP0 |= MCHP_ESPI_GBL_CAP0_FC_SUPP; |
| ESPI_CAP_REGS->GLB_CAP0 |= MCHP_ESPI_FC_CAP_MAX_PLD_SZ_64; |
| ESPI_CAP_REGS->FC_CAP |= MCHP_ESPI_FC_CAP_SHARE_MAF_SAF; |
| ESPI_CAP_REGS->FC_CAP |= MCHP_ESPI_FC_CAP_MAX_RD_SZ_64; |
| |
| k_sem_init(&data->flash_lock, 0, 1); |
| #else |
| ESPI_CAP_REGS->GLB_CAP0 &= ~MCHP_ESPI_GBL_CAP0_FC_SUPP; |
| #endif |
| |
| /* Clear reset interrupt status and enable interrupts */ |
| ESPI_CAP_REGS->ERST_STS = MCHP_ESPI_RST_ISTS; |
| ESPI_CAP_REGS->ERST_IEN |= MCHP_ESPI_RST_IEN; |
| ESPI_PC_REGS->PC_STATUS = MCHP_ESPI_PC_STS_EN_CHG; |
| ESPI_PC_REGS->PC_IEN |= MCHP_ESPI_PC_IEN_EN_CHG; |
| |
| /* Enable VWires interrupts */ |
| for (int i = 0; i < sizeof(vw_wires_int_en); i++) { |
| uint8_t signal = vw_wires_int_en[i]; |
| struct xec_signal signal_info = vw_tbl[signal]; |
| uint8_t xec_id = signal_info.xec_reg_idx; |
| ESPI_MSVW_REG *reg = &(ESPI_M2S_VW_REGS->MSVW00) + xec_id; |
| |
| mec_espi_msvw_irq_sel_set(reg, signal_info.bit, |
| MSVW_IRQ_SEL_EDGE_BOTH); |
| } |
| |
| /* Enable interrupts for each logical channel enable assertion */ |
| MCHP_GIRQ_ENSET(config->bus_girq_id) = MCHP_ESPI_ESPI_RST_GIRQ_VAL | |
| MCHP_ESPI_VW_EN_GIRQ_VAL | MCHP_ESPI_PC_GIRQ_VAL; |
| |
| #ifdef CONFIG_ESPI_OOB_CHANNEL |
| espi_init_oob(dev); |
| #endif |
| #ifdef CONFIG_ESPI_FLASH_CHANNEL |
| espi_init_flash(dev); |
| #endif |
| /* Enable aggregated block interrupts for VWires */ |
| MCHP_GIRQ_ENSET(config->vw_girq_ids[0]) = MEC_ESPI_MSVW00_SRC0_VAL | |
| MEC_ESPI_MSVW00_SRC1_VAL | MEC_ESPI_MSVW00_SRC2_VAL | |
| MEC_ESPI_MSVW01_SRC1_VAL | MEC_ESPI_MSVW01_SRC2_VAL | |
| MEC_ESPI_MSVW02_SRC0_VAL | MEC_ESPI_MSVW03_SRC0_VAL; |
| |
| /* Enable aggregated block interrupts for peripherals supported */ |
| #ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC |
| MCHP_GIRQ_ENSET(config->pc_girq_id) = MCHP_KBC_IBF_GIRQ; |
| #endif |
| #ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO |
| MCHP_GIRQ_ENSET(config->pc_girq_id) = MCHP_ACPI_EC_0_IBF_GIRQ; |
| MCHP_GIRQ_ENSET(config->pc_girq_id) = MCHP_ACPI_EC_2_IBF_GIRQ; |
| #endif |
| #ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT |
| MCHP_GIRQ_ENSET(config->pc_girq_id) = MCHP_ACPI_EC_1_IBF_GIRQ; |
| #endif |
| #ifdef CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80 |
| MCHP_GIRQ_ENSET(config->pc_girq_id) = MCHP_PORT80_DEBUG0_GIRQ_VAL | |
| MCHP_PORT80_DEBUG1_GIRQ_VAL; |
| #endif |
| /* Enable aggregated interrupt block for eSPI bus events */ |
| MCHP_GIRQ_BLK_SETEN(config->bus_girq_id); |
| IRQ_CONNECT(DT_INST_IRQN(0), |
| DT_INST_IRQ(0, priority), |
| espi_xec_bus_isr, |
| DEVICE_DT_INST_GET(0), 0); |
| irq_enable(DT_INST_IRQN(0)); |
| |
| /* Enable aggregated interrupt block for eSPI VWire events */ |
| MCHP_GIRQ_BLK_SETEN(config->vw_girq_ids[0]); |
| IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 1, irq), |
| DT_INST_IRQ_BY_IDX(0, 1, priority), |
| espi_xec_vw_isr, |
| DEVICE_DT_INST_GET(0), 0); |
| irq_enable(DT_INST_IRQ_BY_IDX(0, 1, irq)); |
| |
| /* Enable aggregated interrupt block for eSPI peripheral channel */ |
| MCHP_GIRQ_BLK_SETEN(config->pc_girq_id); |
| IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 2, irq), |
| DT_INST_IRQ_BY_IDX(0, 2, priority), |
| espi_xec_periph_isr, |
| DEVICE_DT_INST_GET(0), 0); |
| irq_enable(DT_INST_IRQ_BY_IDX(0, 2, irq)); |
| |
| #if DT_INST_PROP_HAS_IDX(0, vw_girqs, 1) |
| MCHP_GIRQ_ENSET(config->vw_girq_ids[1]) = MEC_ESPI_MSVW08_SRC1_VAL; |
| MCHP_GIRQ_BLK_SETEN(config->vw_girq_ids[1]); |
| IRQ_CONNECT(DT_INST_IRQ_BY_IDX(0, 3, irq), |
| DT_INST_IRQ_BY_IDX(0, 3, priority), |
| espi_xec_vw_ext_isr, |
| DEVICE_DT_INST_GET(0), 0); |
| irq_enable(DT_INST_IRQ_BY_IDX(0, 3, irq)); |
| #endif |
| |
| return 0; |
| } |