diff --git a/drivers/espi/espi_it8xxx2.c b/drivers/espi/espi_it8xxx2.c index 7372deecc30..5ae9aadd7b7 100644 --- a/drivers/espi/espi_it8xxx2.c +++ b/drivers/espi/espi_it8xxx2.c @@ -9,8 +9,10 @@ #include #include #include +#include #include #include +#include #include "soc_espi.h" #include "espi_utils.h" @@ -28,6 +30,7 @@ LOG_MODULE_REGISTER(espi, CONFIG_ESPI_LOG_LEVEL); #define IT8XXX2_PMC1_IBF_IRQ DT_INST_IRQ_BY_IDX(0, 4, irq) #define IT8XXX2_PORT_80_IRQ DT_INST_IRQ_BY_IDX(0, 5, irq) #define IT8XXX2_PMC2_IBF_IRQ DT_INST_IRQ_BY_IDX(0, 6, irq) +#define IT8XXX2_TRANS_IRQ DT_INST_IRQ_BY_IDX(0, 7, irq) /* General Capabilities and Configuration 1 */ #define IT8XXX2_ESPI_MAX_FREQ_MASK GENMASK(2, 0) @@ -72,6 +75,13 @@ LOG_MODULE_REGISTER(espi, CONFIG_ESPI_LOG_LEVEL); #define IT8XXX2_ESPI_PUT_FLASH_TAG_MASK GENMASK(7, 4) #define IT8XXX2_ESPI_PUT_FLASH_LEN_MASK GENMASK(6, 0) +struct espi_it8xxx2_wuc { + /* WUC control device structure */ + const struct device *wucs; + /* WUC pin mask */ + uint8_t mask; +}; + struct espi_it8xxx2_config { uintptr_t base_espi_slave; uintptr_t base_espi_vw; @@ -81,6 +91,7 @@ struct espi_it8xxx2_config { uintptr_t base_kbc; uintptr_t base_pmc; uintptr_t base_smfi; + const struct espi_it8xxx2_wuc wuc; }; struct espi_it8xxx2_data { @@ -1755,6 +1766,28 @@ void espi_it8xxx2_enable_pad_ctrl(const struct device *dev, bool enable) } } +void espi_it8xxx2_enable_trans_irq(const struct device *dev, bool enable) +{ + const struct espi_it8xxx2_config *const config = dev->config; + + if (enable) { + irq_enable(IT8XXX2_TRANS_IRQ); + } else { + irq_disable(IT8XXX2_TRANS_IRQ); + /* Clear pending interrupt */ + it8xxx2_wuc_clear_status(config->wuc.wucs, config->wuc.mask); + } +} + +static void espi_it8xxx2_trans_isr(const struct device *dev) +{ + /* + * This interrupt is only used to wake up CPU, there is no need to do + * anything in the isr in addition to disable interrupt. + */ + espi_it8xxx2_enable_trans_irq(dev, false); +} + void espi_it8xxx2_espi_reset_isr(const struct device *port, struct gpio_callback *cb, uint32_t pins) { @@ -1804,6 +1837,7 @@ static const struct espi_it8xxx2_config espi_it8xxx2_config_0 = { .base_kbc = DT_INST_REG_ADDR_BY_IDX(0, 5), .base_pmc = DT_INST_REG_ADDR_BY_IDX(0, 6), .base_smfi = DT_INST_REG_ADDR_BY_IDX(0, 7), + .wuc = IT8XXX2_DT_WUC_ITEMS_FUNC(0, 0), }; DEVICE_DT_INST_DEFINE(0, &espi_it8xxx2_init, NULL, @@ -1884,7 +1918,15 @@ static int espi_it8xxx2_init(const struct device *dev) */ slave_reg->ESGCTRL2 |= IT8XXX2_ESPI_TO_WUC_ENABLE; - /* TODO: enable WU42 of WUI */ + /* Enable WU42 of WUI */ + it8xxx2_wuc_clear_status(config->wuc.wucs, config->wuc.mask); + it8xxx2_wuc_enable(config->wuc.wucs, config->wuc.mask); + /* + * Only register isr here, the interrupt only need to be enabled + * before CPU and RAM clocks gated in the idle function. + */ + IRQ_CONNECT(IT8XXX2_TRANS_IRQ, 0, espi_it8xxx2_trans_isr, + DEVICE_DT_INST_GET(0), 0); return 0; } diff --git a/dts/bindings/espi/ite,it8xxx2-espi.yaml b/dts/bindings/espi/ite,it8xxx2-espi.yaml new file mode 100644 index 00000000000..8a772db2573 --- /dev/null +++ b/dts/bindings/espi/ite,it8xxx2-espi.yaml @@ -0,0 +1,14 @@ +# Copyright (c) 2023 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +description: ITE IT8XXX2 ESPI controller + +compatible: "ite,it8xxx2-espi" + +include: espi-controller.yaml + +properties: + wucctrl: + type: phandles + description: | + eSPI node WUC interrupt. diff --git a/dts/riscv/ite/it8xxx2-wuc-map.dtsi b/dts/riscv/ite/it8xxx2-wuc-map.dtsi index fbc5e1d68f9..f5b0ae79967 100644 --- a/dts/riscv/ite/it8xxx2-wuc-map.dtsi +++ b/dts/riscv/ite/it8xxx2-wuc-map.dtsi @@ -61,6 +61,9 @@ wuc_wu40: wu40 { wucs = <&wuc4 BIT(0)>; /* GPE5 */ }; + wuc_wu42: wu42 { + wucs = <&wuc4 BIT(2)>; /* eSPI transaction */ + }; wuc_wu45: wu45 { wucs = <&wuc4 BIT(5)>; /* GPE6 */ }; diff --git a/dts/riscv/ite/it8xxx2.dtsi b/dts/riscv/ite/it8xxx2.dtsi index da12cea7396..7d823bec3c0 100644 --- a/dts/riscv/ite/it8xxx2.dtsi +++ b/dts/riscv/ite/it8xxx2.dtsi @@ -430,8 +430,10 @@ IT8XXX2_IRQ_KBC_OBE IRQ_TYPE_LEVEL_HIGH IT8XXX2_IRQ_PMC1_IBF IRQ_TYPE_LEVEL_HIGH IT8XXX2_IRQ_PCH_P80 IRQ_TYPE_LEVEL_HIGH - IT8XXX2_IRQ_PMC2_IBF IRQ_TYPE_LEVEL_HIGH>; + IT8XXX2_IRQ_PMC2_IBF IRQ_TYPE_LEVEL_HIGH + IT8XXX2_IRQ_WKINTD IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&intc>; + wucctrl = <&wuc_wu42>; #address-cells = <1>; #size-cells = <1>; status = "disabled"; diff --git a/include/zephyr/dt-bindings/interrupt-controller/ite-intc.h b/include/zephyr/dt-bindings/interrupt-controller/ite-intc.h index 6e6e1db7c0b..b3003ca640c 100644 --- a/include/zephyr/dt-bindings/interrupt-controller/ite-intc.h +++ b/include/zephyr/dt-bindings/interrupt-controller/ite-intc.h @@ -18,6 +18,7 @@ #define IT8XXX2_IRQ_WU20 1 #define IT8XXX2_IRQ_KBC_OBE 2 #define IT8XXX2_IRQ_SMB_D 4 +#define IT8XXX2_IRQ_WKINTD 5 #define IT8XXX2_IRQ_WU23 6 /* Group 1 */ #define IT8XXX2_IRQ_SMB_A 9 diff --git a/soc/riscv/riscv-ite/common/soc_espi.h b/soc/riscv/riscv-ite/common/soc_espi.h index 6a0af2103dc..0b88f9473ac 100644 --- a/soc/riscv/riscv-ite/common/soc_espi.h +++ b/soc/riscv/riscv-ite/common/soc_espi.h @@ -24,6 +24,14 @@ extern "C" { */ void espi_it8xxx2_enable_pad_ctrl(const struct device *dev, bool enable); +/** + * @brief eSPI transaction interrupt control + * + * @param dev pointer to eSPI device + * @param enable/disable eSPI transaction interrupt + */ +void espi_it8xxx2_enable_trans_irq(const struct device *dev, bool enable); + #ifdef __cplusplus } #endif diff --git a/soc/riscv/riscv-ite/it8xxx2/soc.c b/soc/riscv/riscv-ite/it8xxx2/soc.c index a8ad7f2cd13..42a03b4f27b 100644 --- a/soc/riscv/riscv-ite/it8xxx2/soc.c +++ b/soc/riscv/riscv-ite/it8xxx2/soc.c @@ -207,6 +207,15 @@ void riscv_idle(enum chip_pll_mode mode, unsigned int key) */ csr_clear(mie, MIP_MEIP); sys_trace_idle(); +#ifdef CONFIG_ESPI + /* + * H2RAM feature requires RAM clock to be active. Since the below doze + * mode will disable CPU and RAM clocks, enable eSPI transaction + * interrupt to restore clocks. With this interrupt, EC will not defer + * eSPI bus while transaction is accepted. + */ + espi_it8xxx2_enable_trans_irq(ESPI_IT8XXX2_SOC_DEV, true); +#endif /* Chip doze after wfi instruction */ chip_pll_ctrl(mode); @@ -223,6 +232,10 @@ void riscv_idle(enum chip_pll_mode mode, unsigned int key) */ } while (ite_intc_no_irq()); +#ifdef CONFIG_ESPI + /* CPU has been woken up, the interrupt is no longer needed */ + espi_it8xxx2_enable_trans_irq(ESPI_IT8XXX2_SOC_DEV, false); +#endif /* * Enable M-mode external interrupt * An interrupt can not be fired yet until we enable global interrupt