From a41a4e5e2446316b83efe1960228a4e140b07201 Mon Sep 17 00:00:00 2001 From: Dino Li Date: Mon, 16 Jan 2023 10:20:21 +0800 Subject: [PATCH] espi: it8xxx2: enable espi transaction interrupt The interrupt is used to wake up EC from low power mode. So EC does not defer eSPI bus while transaction is accepted. Fixes EC host commands slow issue. Signed-off-by: Dino Li --- drivers/espi/espi_it8xxx2.c | 44 ++++++++++++++++++- dts/bindings/espi/ite,it8xxx2-espi.yaml | 14 ++++++ dts/riscv/ite/it8xxx2-wuc-map.dtsi | 3 ++ dts/riscv/ite/it8xxx2.dtsi | 4 +- .../interrupt-controller/ite-intc.h | 1 + soc/riscv/riscv-ite/common/soc_espi.h | 8 ++++ soc/riscv/riscv-ite/it8xxx2/soc.c | 13 ++++++ 7 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 dts/bindings/espi/ite,it8xxx2-espi.yaml 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