From 6d8f1bf6d9fca0ff8a0b0de9bcb6e76e6077919a Mon Sep 17 00:00:00 2001 From: Dino Li Date: Wed, 3 Nov 2021 14:19:07 +0800 Subject: [PATCH] soc: it8xxx2: add support for eSPI driver This supports eSPI slave, virtual wire, and peripheral functions. Signed-off-by: Dino Li --- drivers/espi/CMakeLists.txt | 1 + drivers/espi/Kconfig | 2 + drivers/espi/Kconfig.it8xxx2 | 27 + drivers/espi/espi_it8xxx2.c | 1286 +++++++++++++++++ dts/riscv/it8xxx2.dtsi | 22 + .../interrupt-controller/ite-intc.h | 6 + soc/riscv/riscv-ite/common/check_regs.c | 54 + soc/riscv/riscv-ite/common/chip_chipregs.h | 608 +++++--- soc/riscv/riscv-ite/common/soc_espi.h | 31 + soc/riscv/riscv-ite/it8xxx2/soc.c | 9 +- 10 files changed, 1879 insertions(+), 167 deletions(-) create mode 100644 drivers/espi/Kconfig.it8xxx2 create mode 100644 drivers/espi/espi_it8xxx2.c create mode 100644 soc/riscv/riscv-ite/common/soc_espi.h diff --git a/drivers/espi/CMakeLists.txt b/drivers/espi/CMakeLists.txt index 5ba46d2615f..82e257098f3 100644 --- a/drivers/espi/CMakeLists.txt +++ b/drivers/espi/CMakeLists.txt @@ -10,3 +10,4 @@ zephyr_library_sources_ifdef(CONFIG_ESPI_EMUL espi_emul.c) zephyr_library_sources_ifdef(CONFIG_ESPI_SAF espi_saf_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_ESPI_XEC_V2 espi_mchp_xec_v2.c) zephyr_library_sources_ifdef(CONFIG_ESPI_XEC_V2 espi_mchp_xec_host_v2.c) +zephyr_library_sources_ifdef(CONFIG_ESPI_IT8XXX2 espi_it8xxx2.c) diff --git a/drivers/espi/Kconfig b/drivers/espi/Kconfig index 6a8c2ecac9f..5502dfb0c38 100644 --- a/drivers/espi/Kconfig +++ b/drivers/espi/Kconfig @@ -18,6 +18,8 @@ source "drivers/espi/Kconfig.npcx" source "drivers/espi/Kconfig.espi_emul" +source "drivers/espi/Kconfig.it8xxx2" + module = ESPI module-str = espi source "subsys/logging/Kconfig.template.log_config" diff --git a/drivers/espi/Kconfig.it8xxx2 b/drivers/espi/Kconfig.it8xxx2 new file mode 100644 index 00000000000..1ba12671905 --- /dev/null +++ b/drivers/espi/Kconfig.it8xxx2 @@ -0,0 +1,27 @@ +# Copyright (c) 2021 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +config ESPI_IT8XXX2 + bool "ITE IT8XXX2 embedded controller ESPI driver" + depends on SOC_IT8XXX2 + help + Enable ITE IT8XXX2 ESPI driver. + +if ESPI_IT8XXX2 + +config ESPI_PERIPHERAL_8042_KBC + default y + +config ESPI_PERIPHERAL_HOST_IO + default y + +config ESPI_PERIPHERAL_DEBUG_PORT_80 + default y + +config ESPI_IT8XXX2_PNPCFG_DEVICE_KBC_MOUSE + bool "ITE IT8XXX2 KBC mouse device" + help + With this option enabled, EC will send IRQ12 signal to host when the + KBC mouse output buffer is full. + +endif #ESPI_IT8XXX2 diff --git a/drivers/espi/espi_it8xxx2.c b/drivers/espi/espi_it8xxx2.c new file mode 100644 index 00000000000..c6c24910219 --- /dev/null +++ b/drivers/espi/espi_it8xxx2.c @@ -0,0 +1,1286 @@ +/* + * Copyright (c) 2021 ITE Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ite_it8xxx2_espi + +#include +#include +#include +#include +#include +#include "soc_espi.h" +#include "espi_utils.h" + +#include +LOG_MODULE_REGISTER(espi, CONFIG_ESPI_LOG_LEVEL); + +#define ESPI_IT8XXX2_GET_GCTRL_BASE \ + ((struct gctrl_it8xxx2_regs *)DT_REG_ADDR(DT_NODELABEL(gctrl))) + +#define IT8XXX2_ESPI_IRQ DT_INST_IRQ_BY_IDX(0, 0, irq) +#define IT8XXX2_ESPI_VW_IRQ DT_INST_IRQ_BY_IDX(0, 1, irq) +#define IT8XXX2_KBC_IBF_IRQ DT_INST_IRQ_BY_IDX(0, 2, irq) +#define IT8XXX2_KBC_OBE_IRQ DT_INST_IRQ_BY_IDX(0, 3, irq) +#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) + +/* General Capabilities and Configuration 1 */ +#define IT8XXX2_ESPI_MAX_FREQ_MASK GENMASK(2, 0) +#define IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_20 0 +#define IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_25 1 +#define IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_33 2 +#define IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_50 3 +#define IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_66 4 + +#define IT8XXX2_ESPI_PC_READY_MASK BIT(1) +#define IT8XXX2_ESPI_VW_READY_MASK BIT(1) +#define IT8XXX2_ESPI_OOB_READY_MASK BIT(1) +#define IT8XXX2_ESPI_FC_READY_MASK BIT(1) + +#define IT8XXX2_ESPI_INTERRUPT_ENABLE BIT(7) +#define IT8XXX2_ESPI_TO_WUC_ENABLE BIT(4) +#define IT8XXX2_ESPI_VW_INTERRUPT_ENABLE BIT(7) +#define IT8XXX2_ESPI_INTERRUPT_PUT_PC BIT(7) + +#define IT8XXX2_ESPI_UPSTREAM_INTERRUPT_ENABLE BIT(5) +#define IT8XXX2_ESPI_UPSTREAM_CHANNEL_DISABLE BIT(2) +#define IT8XXX2_ESPI_UPSTREAM_DONE BIT(1) + +#define IT8XXX2_ESPI_PUT_OOB_STATUS BIT(7) +#define IT8XXX2_ESPI_PUT_OOB_INTERRUPT_ENABLE BIT(7) + +#define IT8XXX2_ESPI_INPUT_PAD_GATING BIT(6) + +struct espi_it8xxx2_config { + uintptr_t base_espi_slave; + uintptr_t base_espi_vw; + uintptr_t base_espi_queue1; + uintptr_t base_espi_queue0; + uintptr_t base_ec2i; + uintptr_t base_kbc; + uintptr_t base_pmc; +}; + +struct espi_it8xxx2_data { + sys_slist_t callbacks; +}; + +/* Driver convenience defines */ +#define DRV_CONFIG(dev) ((const struct espi_it8xxx2_config *)(dev)->config) +#define DRV_DATA(dev) ((struct espi_it8xxx2_data *)(dev)->data) + +struct vw_channel_t { + uint8_t vw_index; /* VW index of signal */ + uint8_t level_mask; /* level bit of signal */ + uint8_t valid_mask; /* valid bit of signal */ +}; + +struct vwidx_isr_t { + void (*vwidx_isr)(const struct device *dev, uint8_t update_flag); + uint8_t vw_index; +}; + +enum espi_ch_enable_isr_type { + DEASSERTED_FLAG = 0, + ASSERTED_FLAG = 1, +}; + +struct espi_isr_t { + void (*espi_isr)(const struct device *dev, bool enable); + enum espi_ch_enable_isr_type isr_type; +}; + +struct espi_vw_signal_t { + enum espi_vwire_signal signal; + void (*vw_signal_isr)(const struct device *dev); +}; + +/* EC2I bridge and PNPCFG devices */ +static const struct ec2i_t kbc_settings[] = { + /* Select logical device 06h(keyboard) */ + {HOST_INDEX_LDN, LDN_KBC_KEYBOARD}, + /* Set IRQ=01h for logical device */ + {HOST_INDEX_IRQNUMX, 0x01}, + /* Configure IRQTP for KBC. */ + /* + * Interrupt request type select (IRQTP) for KBC. + * bit 1, 0: IRQ request is buffered and applied to SERIRQ + * 1: IRQ request is inverted before being applied to SERIRQ + * bit 0, 0: Edge triggered mode + * 1: Level triggered mode + * + * This interrupt configuration should the same on both host and EC side + */ + {HOST_INDEX_IRQTP, 0x02}, + /* Enable logical device */ + {HOST_INDEX_LDA, 0x01}, + +#ifdef CONFIG_ESPI_IT8XXX2_PNPCFG_DEVICE_KBC_MOUSE + /* Select logical device 05h(mouse) */ + {HOST_INDEX_LDN, LDN_KBC_MOUSE}, + /* Set IRQ=0Ch for logical device */ + {HOST_INDEX_IRQNUMX, 0x0C}, + /* Enable logical device */ + {HOST_INDEX_LDA, 0x01}, +#endif +}; + +static const struct ec2i_t pmc1_settings[] = { + /* Select logical device 11h(PM1 ACPI) */ + {HOST_INDEX_LDN, LDN_PMC1}, + /* Set IRQ=00h for logical device */ + {HOST_INDEX_IRQNUMX, 0x00}, + /* Enable logical device */ + {HOST_INDEX_LDA, 0x01}, +}; + +static void ec2i_it8xxx2_wait_status_cleared(const struct device *dev, + uint8_t mask) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct ec2i_regs *const ec2i = (struct ec2i_regs *)config->base_ec2i; + + while (ec2i->IBCTL & mask) { + ; + } +} + +static void ec2i_it8xxx2_write_pnpcfg(const struct device *dev, + enum ec2i_access sel, uint8_t data) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct ec2i_regs *const ec2i = (struct ec2i_regs *)config->base_ec2i; + + /* bit0: EC to I-Bus access enabled. */ + ec2i->IBCTL |= EC2I_IBCTL_CSAE; + /* + * Wait that both CRIB and CWIB bits in IBCTL register + * are cleared. + */ + ec2i_it8xxx2_wait_status_cleared(dev, EC2I_IBCTL_CRWIB); + /* Enable EC access to the PNPCFG registers */ + ec2i->IBMAE |= EC2I_IBMAE_CFGAE; + /* Set indirect host I/O offset. */ + ec2i->IHIOA = sel; + /* Write the data to IHD register */ + ec2i->IHD = data; + /* Wait the CWIB bit in IBCTL cleared. */ + ec2i_it8xxx2_wait_status_cleared(dev, EC2I_IBCTL_CWIB); + /* Disable EC access to the PNPCFG registers. */ + ec2i->IBMAE &= ~EC2I_IBMAE_CFGAE; + /* Disable EC to I-Bus access. */ + ec2i->IBCTL &= ~EC2I_IBCTL_CSAE; +} + +static void ec2i_it8xxx2_write(const struct device *dev, + enum host_pnpcfg_index index, uint8_t data) +{ + /* Set index */ + ec2i_it8xxx2_write_pnpcfg(dev, EC2I_ACCESS_INDEX, index); + /* Set data */ + ec2i_it8xxx2_write_pnpcfg(dev, EC2I_ACCESS_DATA, data); +} + +static void pnpcfg_it8xxx2_configure(const struct device *dev, + const struct ec2i_t *settings, + size_t entries) +{ + for (size_t i = 0; i < entries; i++) { + ec2i_it8xxx2_write(dev, settings[i].index_port, + settings[i].data_port); + } +} + +#define PNPCFG(_s) \ + pnpcfg_it8xxx2_configure(dev, _s##_settings, ARRAY_SIZE(_s##_settings)) + +static void pnpcfg_it8xxx2_init(const struct device *dev) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct ec2i_regs *const ec2i = (struct ec2i_regs *)config->base_ec2i; + struct gctrl_it8xxx2_regs *const gctrl = ESPI_IT8XXX2_GET_GCTRL_BASE; + + /* The register pair to access PNPCFG is 004Eh and 004Fh */ + gctrl->GCTRL_BADRSEL = 0x1; + /* Host access is disabled */ + ec2i->LSIOHA |= 0x3; + /* configure pnpcfg devices */ + if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_8042_KBC)) { + PNPCFG(kbc); + } + if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_HOST_IO)) { + PNPCFG(pmc1); + } +} + +/* KBC (port 60h/64h) */ +#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC +static void kbc_it8xxx2_ibf_isr(const struct device *dev) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_it8xxx2_data *const data = DRV_DATA(dev); + struct kbc_regs *const kbc_reg = (struct kbc_regs *)config->base_kbc; + struct espi_event evt = { + ESPI_BUS_PERIPHERAL_NOTIFICATION, + ESPI_PERIPHERAL_8042_KBC, + ESPI_PERIPHERAL_NODATA + }; + struct espi_evt_data_kbc *kbc_evt = + (struct espi_evt_data_kbc *)&evt.evt_data; + + /* KBC Input Buffer Full event */ + kbc_evt->evt = HOST_KBC_EVT_IBF; + /* The data in KBC Input Buffer */ + kbc_evt->data = kbc_reg->KBHIDIR; + /* + * Indicates if the host sent a command or data. + * 0 = data + * 1 = Command. + */ + kbc_evt->type = !!(kbc_reg->KBHISR & KBC_KBHISR_A2_ADDR); + + espi_send_callbacks(&data->callbacks, dev, evt); +} + +static void kbc_it8xxx2_obe_isr(const struct device *dev) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_it8xxx2_data *const data = DRV_DATA(dev); + struct kbc_regs *const kbc_reg = (struct kbc_regs *)config->base_kbc; + struct espi_event evt = { + ESPI_BUS_PERIPHERAL_NOTIFICATION, + ESPI_PERIPHERAL_8042_KBC, + ESPI_PERIPHERAL_NODATA + }; + struct espi_evt_data_kbc *kbc_evt = + (struct espi_evt_data_kbc *)&evt.evt_data; + + /* Disable KBC OBE interrupt first */ + kbc_reg->KBHICR &= ~KBC_KBHICR_OBECIE; + + /* Notify application that host already read out data. */ + kbc_evt->evt = HOST_KBC_EVT_OBE; + kbc_evt->data = 0; + kbc_evt->type = 0; + espi_send_callbacks(&data->callbacks, dev, evt); +} + +static void kbc_it8xxx2_init(const struct device *dev) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct kbc_regs *const kbc_reg = (struct kbc_regs *)config->base_kbc; + + /* Disable KBC serirq IRQ */ + kbc_reg->KBIRQR = 0; + + /* + * bit3: Input Buffer Full CPU Interrupt Enable. + * bit1: Enable the interrupt to mouse driver in the host processor via + * SERIRQ when the output buffer is full. + * bit0: Enable the interrupt to keyboard driver in the host processor + * via SERIRQ when the output buffer is full + */ + kbc_reg->KBHICR |= + (KBC_KBHICR_IBFCIE | KBC_KBHICR_OBFKIE | KBC_KBHICR_OBFMIE); + + /* Input Buffer Full CPU Interrupt Enable. */ + IRQ_CONNECT(IT8XXX2_KBC_IBF_IRQ, 0, kbc_it8xxx2_ibf_isr, + DEVICE_DT_INST_GET(0), 0); + irq_enable(IT8XXX2_KBC_IBF_IRQ); + + /* Output Buffer Empty CPU Interrupt Enable */ + IRQ_CONNECT(IT8XXX2_KBC_OBE_IRQ, 0, kbc_it8xxx2_obe_isr, + DEVICE_DT_INST_GET(0), 0); + irq_enable(IT8XXX2_KBC_OBE_IRQ); +} +#endif + +/* PMC 1 (APCI port 62h/66h) */ +#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO +static void pmc1_it8xxx2_ibf_isr(const struct device *dev) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_it8xxx2_data *const data = DRV_DATA(dev); + struct pmc_regs *const pmc_reg = (struct pmc_regs *)config->base_pmc; + struct espi_event evt = { + ESPI_BUS_PERIPHERAL_NOTIFICATION, + ESPI_PERIPHERAL_HOST_IO, + ESPI_PERIPHERAL_NODATA + }; + struct espi_evt_data_acpi *acpi_evt = + (struct espi_evt_data_acpi *)&evt.evt_data; + + /* + * Indicates if the host sent a command or data. + * 0 = data + * 1 = Command. + */ + acpi_evt->type = !!(pmc_reg->PM1STS & PMC_PM1STS_A2_ADDR); + /* Set processing flag before reading command byte */ + pmc_reg->PM1STS |= PMC_PM1STS_GPF; + acpi_evt->data = pmc_reg->PM1DI; + + espi_send_callbacks(&data->callbacks, dev, evt); +} + +static void pmc1_it8xxx2_init(const struct device *dev) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct pmc_regs *const pmc_reg = (struct pmc_regs *)config->base_pmc; + + /* Enable pmc1 input buffer full interrupt */ + pmc_reg->PM1CTL |= PMC_PM1CTL_IBFIE; + IRQ_CONNECT(IT8XXX2_PMC1_IBF_IRQ, 0, pmc1_it8xxx2_ibf_isr, + DEVICE_DT_INST_GET(0), 0); + irq_enable(IT8XXX2_PMC1_IBF_IRQ); +} +#endif + +/* Port 80 */ +#ifdef CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80 +static void port80_it8xxx2_isr(const struct device *dev) +{ + struct espi_it8xxx2_data *const data = DRV_DATA(dev); + struct gctrl_it8xxx2_regs *const gctrl = ESPI_IT8XXX2_GET_GCTRL_BASE; + struct espi_event evt = { + ESPI_BUS_PERIPHERAL_NOTIFICATION, + (ESPI_PERIPHERAL_INDEX_0 << 16) | ESPI_PERIPHERAL_DEBUG_PORT80, + ESPI_PERIPHERAL_NODATA + }; + + evt.evt_data = gctrl->GCTRL_P80HDR; + /* Write 1 to clear this bit */ + gctrl->GCTRL_P80H81HSR |= BIT(0); + + espi_send_callbacks(&data->callbacks, dev, evt); +} + +static void port80_it8xxx2_init(const struct device *dev) +{ + ARG_UNUSED(dev); + struct gctrl_it8xxx2_regs *const gctrl = ESPI_IT8XXX2_GET_GCTRL_BASE; + + /* Accept Port 80h Cycle */ + gctrl->GCTRL_SPCTRL1 |= IT8XXX2_GCTRL_ACP80; + IRQ_CONNECT(IT8XXX2_PORT_80_IRQ, 0, port80_it8xxx2_isr, + DEVICE_DT_INST_GET(0), 0); + irq_enable(IT8XXX2_PORT_80_IRQ); +} +#endif + +/* eSPI api functions */ +#define VW_CHAN(signal, index, level, valid) \ + [signal] = {.vw_index = index, .level_mask = level, .valid_mask = valid} + +/* VW signals used in eSPI */ +static const struct vw_channel_t vw_channel_list[] = { + VW_CHAN(ESPI_VWIRE_SIGNAL_SLP_S3, 0x02, BIT(0), BIT(4)), + VW_CHAN(ESPI_VWIRE_SIGNAL_SLP_S4, 0x02, BIT(1), BIT(5)), + VW_CHAN(ESPI_VWIRE_SIGNAL_SLP_S5, 0x02, BIT(2), BIT(6)), + VW_CHAN(ESPI_VWIRE_SIGNAL_OOB_RST_WARN, 0x03, BIT(2), BIT(6)), + VW_CHAN(ESPI_VWIRE_SIGNAL_PLTRST, 0x03, BIT(1), BIT(5)), + VW_CHAN(ESPI_VWIRE_SIGNAL_SUS_STAT, 0x03, BIT(0), BIT(4)), + VW_CHAN(ESPI_VWIRE_SIGNAL_NMIOUT, 0x07, BIT(2), BIT(6)), + VW_CHAN(ESPI_VWIRE_SIGNAL_SMIOUT, 0x07, BIT(1), BIT(5)), + VW_CHAN(ESPI_VWIRE_SIGNAL_HOST_RST_WARN, 0x07, BIT(0), BIT(4)), + VW_CHAN(ESPI_VWIRE_SIGNAL_SLP_A, 0x41, BIT(3), BIT(7)), + VW_CHAN(ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK, 0x41, BIT(1), BIT(5)), + VW_CHAN(ESPI_VWIRE_SIGNAL_SUS_WARN, 0x41, BIT(0), BIT(4)), + VW_CHAN(ESPI_VWIRE_SIGNAL_SLP_WLAN, 0x42, BIT(1), BIT(5)), + VW_CHAN(ESPI_VWIRE_SIGNAL_SLP_LAN, 0x42, BIT(0), BIT(4)), + VW_CHAN(ESPI_VWIRE_SIGNAL_HOST_C10, 0x47, BIT(0), BIT(4)), + VW_CHAN(ESPI_VWIRE_SIGNAL_DNX_WARN, 0x4a, BIT(1), BIT(5)), + VW_CHAN(ESPI_VWIRE_SIGNAL_PME, 0x04, BIT(3), BIT(7)), + VW_CHAN(ESPI_VWIRE_SIGNAL_WAKE, 0x04, BIT(2), BIT(6)), + VW_CHAN(ESPI_VWIRE_SIGNAL_OOB_RST_ACK, 0x04, BIT(0), BIT(4)), + VW_CHAN(ESPI_VWIRE_SIGNAL_SLV_BOOT_STS, 0x05, BIT(3), BIT(7)), + VW_CHAN(ESPI_VWIRE_SIGNAL_ERR_NON_FATAL, 0x05, BIT(2), BIT(6)), + VW_CHAN(ESPI_VWIRE_SIGNAL_ERR_FATAL, 0x05, BIT(1), BIT(5)), + VW_CHAN(ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, 0x05, BIT(0), BIT(4)), + VW_CHAN(ESPI_VWIRE_SIGNAL_HOST_RST_ACK, 0x06, BIT(3), BIT(7)), + VW_CHAN(ESPI_VWIRE_SIGNAL_RST_CPU_INIT, 0x06, BIT(2), BIT(6)), + VW_CHAN(ESPI_VWIRE_SIGNAL_SMI, 0x06, BIT(1), BIT(5)), + VW_CHAN(ESPI_VWIRE_SIGNAL_SCI, 0x06, BIT(0), BIT(4)), + VW_CHAN(ESPI_VWIRE_SIGNAL_DNX_ACK, 0x40, BIT(1), BIT(5)), + VW_CHAN(ESPI_VWIRE_SIGNAL_SUS_ACK, 0x40, BIT(0), BIT(4)), +}; + +static int espi_it8xxx2_configure(const struct device *dev, + struct espi_cfg *cfg) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_slave_regs *const slave_reg = + (struct espi_slave_regs *)config->base_espi_slave; + uint8_t capcfg1 = 0; + + /* Set frequency */ + switch (cfg->max_freq) { + case 20: + capcfg1 = IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_20; + break; + case 25: + capcfg1 = IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_25; + break; + case 33: + capcfg1 = IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_33; + break; + case 50: + capcfg1 = IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_50; + break; + case 66: + capcfg1 = IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_66; + break; + default: + return -EINVAL; + } + slave_reg->GCAPCFG1 = + (slave_reg->GCAPCFG1 & ~IT8XXX2_ESPI_MAX_FREQ_MASK) | capcfg1; + + /* + * Configure eSPI I/O mode. (Register read only) + * Supported I/O mode : single, dual and quad. + */ + + /* Configure eSPI supported channels. (Register read only) + * Supported channels: peripheral, virtual wire, OOB, and flash access. + */ + + return 0; +} + +static bool espi_it8xxx2_channel_ready(const struct device *dev, + enum espi_channel ch) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_slave_regs *const slave_reg = + (struct espi_slave_regs *)config->base_espi_slave; + bool sts = false; + + switch (ch) { + case ESPI_CHANNEL_PERIPHERAL: + sts = slave_reg->CH_PC_CAPCFG3 & IT8XXX2_ESPI_PC_READY_MASK; + break; + case ESPI_CHANNEL_VWIRE: + sts = slave_reg->CH_VW_CAPCFG3 & IT8XXX2_ESPI_VW_READY_MASK; + break; + case ESPI_CHANNEL_OOB: + sts = slave_reg->CH_OOB_CAPCFG3 & IT8XXX2_ESPI_OOB_READY_MASK; + break; + case ESPI_CHANNEL_FLASH: + sts = slave_reg->CH_FLASH_CAPCFG3 & IT8XXX2_ESPI_FC_READY_MASK; + break; + default: + break; + } + + return sts; +} + +static int espi_vw_set_valid(const struct device *dev, + enum espi_vwire_signal signal, uint8_t valid) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_vw_regs *const vw_reg = + (struct espi_vw_regs *)config->base_espi_vw; + uint8_t vw_index = vw_channel_list[signal].vw_index; + uint8_t valid_mask = vw_channel_list[signal].valid_mask; + + if (signal > ARRAY_SIZE(vw_channel_list)) { + return -EIO; + } + + if (valid) { + vw_reg->VW_INDEX[vw_index] |= valid_mask; + } else { + vw_reg->VW_INDEX[vw_index] &= ~valid_mask; + } + + return 0; +} + +static int espi_it8xxx2_send_vwire(const struct device *dev, + enum espi_vwire_signal signal, uint8_t level) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_vw_regs *const vw_reg = + (struct espi_vw_regs *)config->base_espi_vw; + uint8_t vw_index = vw_channel_list[signal].vw_index; + uint8_t level_mask = vw_channel_list[signal].level_mask; + + if (signal > ARRAY_SIZE(vw_channel_list)) { + return -EIO; + } + + if (level) { + vw_reg->VW_INDEX[vw_index] |= level_mask; + } else { + vw_reg->VW_INDEX[vw_index] &= ~level_mask; + } + + return 0; +} + +static int espi_it8xxx2_receive_vwire(const struct device *dev, + enum espi_vwire_signal signal, uint8_t *level) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_vw_regs *const vw_reg = + (struct espi_vw_regs *)config->base_espi_vw; + uint8_t vw_index = vw_channel_list[signal].vw_index; + uint8_t level_mask = vw_channel_list[signal].level_mask; + uint8_t valid_mask = vw_channel_list[signal].valid_mask; + + if (signal > ARRAY_SIZE(vw_channel_list)) { + return -EIO; + } + + if (vw_reg->VW_INDEX[vw_index] & valid_mask) { + *level = !!(vw_reg->VW_INDEX[vw_index] & level_mask); + } else { + /* Not valid */ + *level = 0; + } + + return 0; +} + +static int espi_it8xxx2_manage_callback(const struct device *dev, + struct espi_callback *callback, bool set) +{ + struct espi_it8xxx2_data *const data = DRV_DATA(dev); + + return espi_manage_callback(&data->callbacks, callback, set); +} + +static int espi_it8xxx2_read_lpc_request(const struct device *dev, + enum lpc_peripheral_opcode op, + uint32_t *data) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + + if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) { + struct kbc_regs *const kbc_reg = + (struct kbc_regs *)config->base_kbc; + + 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_reg->KBHISR & KBC_KBHISR_OBF); + break; + case E8042_IBF_HAS_CHAR: + *data = !!(kbc_reg->KBHISR & KBC_KBHISR_IBF); + break; + case E8042_READ_KB_STS: + *data = kbc_reg->KBHISR; + break; + default: + return -EINVAL; + } + } else if (op >= EACPI_START_OPCODE && op <= EACPI_MAX_OPCODE) { + struct pmc_regs *const pmc_reg = + (struct pmc_regs *)config->base_pmc; + + switch (op) { + case EACPI_OBF_HAS_CHAR: + /* EC has written data back to host. OBF is + * automatically cleared after host reads + * the data + */ + *data = !!(pmc_reg->PM1STS & PMC_PM1STS_OBF); + break; + case EACPI_IBF_HAS_CHAR: + *data = !!(pmc_reg->PM1STS & PMC_PM1STS_IBF); + break; + case EACPI_READ_STS: + *data = pmc_reg->PM1STS; + break; + default: + return -EINVAL; + } + } else { + return -ENOTSUP; + } + + return 0; +} + +static int espi_it8xxx2_write_lpc_request(const struct device *dev, + enum lpc_peripheral_opcode op, + uint32_t *data) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + + if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) { + struct kbc_regs *const kbc_reg = + (struct kbc_regs *)config->base_kbc; + + switch (op) { + case E8042_WRITE_KB_CHAR: + kbc_reg->KBHIKDOR = (*data & 0xff); + /* + * Enable OBE interrupt after putting data in + * data register. + */ + kbc_reg->KBHICR |= KBC_KBHICR_OBECIE; + break; + case E8042_WRITE_MB_CHAR: + kbc_reg->KBHIMDOR = (*data & 0xff); + /* + * Enable OBE interrupt after putting data in + * data register. + */ + kbc_reg->KBHICR |= KBC_KBHICR_OBECIE; + break; + case E8042_RESUME_IRQ: + /* Enable KBC IBF interrupt */ + kbc_reg->KBHICR |= KBC_KBHICR_IBFCIE; + break; + case E8042_PAUSE_IRQ: + /* Disable KBC IBF interrupt */ + kbc_reg->KBHICR &= ~KBC_KBHICR_IBFCIE; + break; + case E8042_CLEAR_OBF: + /* + * When IBFOBFCME is enabled, write 1 to COBF bit to + * clear KBC OBF. + */ + kbc_reg->KBHICR |= KBC_KBHICR_IBFOBFCME; + kbc_reg->KBHICR |= KBC_KBHICR_COBF; + kbc_reg->KBHICR &= ~KBC_KBHICR_COBF; + /* Disable clear mode */ + kbc_reg->KBHICR &= ~KBC_KBHICR_IBFOBFCME; + break; + case E8042_SET_FLAG: + kbc_reg->KBHISR |= (*data & 0xff); + break; + case E8042_CLEAR_FLAG: + kbc_reg->KBHISR &= ~(*data & 0xff); + break; + default: + return -EINVAL; + } + } else if (op >= EACPI_START_OPCODE && op <= EACPI_MAX_OPCODE) { + struct pmc_regs *const pmc_reg = + (struct pmc_regs *)config->base_pmc; + + switch (op) { + case EACPI_WRITE_CHAR: + pmc_reg->PM1DO = (*data & 0xff); + break; + case EACPI_WRITE_STS: + pmc_reg->PM1STS = (*data & 0xff); + break; + default: + return -EINVAL; + } + } else { + return -ENOTSUP; + } + + return 0; +} + +#ifdef CONFIG_ESPI_OOB_CHANNEL +static int espi_it8xxx2_send_oob(const struct device *dev, + struct espi_oob_packet *pckt) +{ + /* TODO: implement me... */ + ARG_UNUSED(dev); + + return -EIO; +} + +static int espi_it8xxx2_receive_oob(const struct device *dev, + struct espi_oob_packet *pckt) +{ + /* TODO: implement me... */ + ARG_UNUSED(dev); + + return -EIO; +} +#endif + +/* eSPI driver registration */ +static int espi_it8xxx2_init(const struct device *dev); + +static const struct espi_driver_api espi_it8xxx2_driver_api = { + .config = espi_it8xxx2_configure, + .get_channel_status = espi_it8xxx2_channel_ready, + .send_vwire = espi_it8xxx2_send_vwire, + .receive_vwire = espi_it8xxx2_receive_vwire, + .manage_callback = espi_it8xxx2_manage_callback, + .read_lpc_request = espi_it8xxx2_read_lpc_request, + .write_lpc_request = espi_it8xxx2_write_lpc_request, +#ifdef CONFIG_ESPI_OOB_CHANNEL + .send_oob = espi_it8xxx2_send_oob, + .receive_oob = espi_it8xxx2_receive_oob, +#endif +}; + +static void espi_it8xxx2_vw_notify_system_state(const struct device *dev, + enum espi_vwire_signal signal) +{ + struct espi_it8xxx2_data *const data = DRV_DATA(dev); + struct espi_event evt = {ESPI_BUS_EVENT_VWIRE_RECEIVED, 0, 0}; + uint8_t level = 0; + + espi_it8xxx2_receive_vwire(dev, signal, &level); + + evt.evt_details = signal; + evt.evt_data = level; + espi_send_callbacks(&data->callbacks, dev, evt); +} + +static void espi_vw_signal_no_isr(const struct device *dev) +{ + ARG_UNUSED(dev); +} + +static const struct espi_vw_signal_t vwidx2_signals[] = { + {ESPI_VWIRE_SIGNAL_SLP_S3, NULL}, + {ESPI_VWIRE_SIGNAL_SLP_S4, NULL}, + {ESPI_VWIRE_SIGNAL_SLP_S5, NULL}, +}; + +static void espi_it8xxx2_vwidx2_isr(const struct device *dev, + uint8_t updated_flag) +{ + for (int i = 0; i < ARRAY_SIZE(vwidx2_signals); i++) { + enum espi_vwire_signal vw_signal = vwidx2_signals[i].signal; + + if (updated_flag & vw_channel_list[vw_signal].level_mask) { + espi_it8xxx2_vw_notify_system_state(dev, vw_signal); + } + } +} + +static void espi_vw_oob_rst_warm_isr(const struct device *dev) +{ + uint8_t level = 0; + + espi_it8xxx2_receive_vwire(dev, ESPI_VWIRE_SIGNAL_OOB_RST_WARN, &level); + espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_OOB_RST_ACK, level); +} + +static void espi_vw_pltrst_isr(const struct device *dev) +{ + uint8_t pltrst = 0; + + espi_it8xxx2_receive_vwire(dev, ESPI_VWIRE_SIGNAL_PLTRST, &pltrst); + + if (pltrst) { + espi_vw_set_valid(dev, ESPI_VWIRE_SIGNAL_SMI, 1); + espi_vw_set_valid(dev, ESPI_VWIRE_SIGNAL_SCI, 1); + espi_vw_set_valid(dev, ESPI_VWIRE_SIGNAL_HOST_RST_ACK, 1); + espi_vw_set_valid(dev, ESPI_VWIRE_SIGNAL_RST_CPU_INIT, 1); + espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_SMI, 1); + espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_SCI, 1); + espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_HOST_RST_ACK, 1); + espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_RST_CPU_INIT, 1); + } + + LOG_INF("VW PLTRST_L %sasserted", pltrst ? "de" : ""); +} + +static const struct espi_vw_signal_t vwidx3_signals[] = { + {ESPI_VWIRE_SIGNAL_OOB_RST_WARN, espi_vw_oob_rst_warm_isr}, + {ESPI_VWIRE_SIGNAL_PLTRST, espi_vw_pltrst_isr}, +}; + +static void espi_it8xxx2_vwidx3_isr(const struct device *dev, + uint8_t updated_flag) +{ + for (int i = 0; i < ARRAY_SIZE(vwidx3_signals); i++) { + enum espi_vwire_signal vw_signal = vwidx3_signals[i].signal; + + if (updated_flag & vw_channel_list[vw_signal].level_mask) { + vwidx3_signals[i].vw_signal_isr(dev); + espi_it8xxx2_vw_notify_system_state(dev, vw_signal); + } + } +} + +static void espi_vw_host_rst_warn_isr(const struct device *dev) +{ + uint8_t level = 0; + + espi_it8xxx2_receive_vwire(dev, + ESPI_VWIRE_SIGNAL_HOST_RST_WARN, &level); + espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_HOST_RST_ACK, level); +} + +static const struct espi_vw_signal_t vwidx7_signals[] = { + {ESPI_VWIRE_SIGNAL_HOST_RST_WARN, espi_vw_host_rst_warn_isr}, +}; + +static void espi_it8xxx2_vwidx7_isr(const struct device *dev, + uint8_t updated_flag) +{ + for (int i = 0; i < ARRAY_SIZE(vwidx7_signals); i++) { + enum espi_vwire_signal vw_signal = vwidx7_signals[i].signal; + + if (updated_flag & vw_channel_list[vw_signal].level_mask) { + vwidx7_signals[i].vw_signal_isr(dev); + espi_it8xxx2_vw_notify_system_state(dev, vw_signal); + } + } +} + +static void espi_vw_sus_warn_isr(const struct device *dev) +{ + uint8_t level = 0; + + espi_it8xxx2_receive_vwire(dev, ESPI_VWIRE_SIGNAL_SUS_WARN, &level); + espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_SUS_ACK, level); +} + +static const struct espi_vw_signal_t vwidx41_signals[] = { + {ESPI_VWIRE_SIGNAL_SUS_WARN, espi_vw_sus_warn_isr}, + {ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK, espi_vw_signal_no_isr}, + {ESPI_VWIRE_SIGNAL_SLP_A, espi_vw_signal_no_isr}, +}; + +static void espi_it8xxx2_vwidx41_isr(const struct device *dev, + uint8_t updated_flag) +{ + for (int i = 0; i < ARRAY_SIZE(vwidx41_signals); i++) { + enum espi_vwire_signal vw_signal = vwidx41_signals[i].signal; + + if (updated_flag & vw_channel_list[vw_signal].level_mask) { + vwidx41_signals[i].vw_signal_isr(dev); + espi_it8xxx2_vw_notify_system_state(dev, vw_signal); + } + } +} + +static const struct espi_vw_signal_t vwidx42_signals[] = { + {ESPI_VWIRE_SIGNAL_SLP_LAN, NULL}, + {ESPI_VWIRE_SIGNAL_SLP_WLAN, NULL}, +}; + +static void espi_it8xxx2_vwidx42_isr(const struct device *dev, + uint8_t updated_flag) +{ + for (int i = 0; i < ARRAY_SIZE(vwidx42_signals); i++) { + enum espi_vwire_signal vw_signal = vwidx42_signals[i].signal; + + if (updated_flag & vw_channel_list[vw_signal].level_mask) { + espi_it8xxx2_vw_notify_system_state(dev, vw_signal); + } + } +} + +static void espi_it8xxx2_vwidx43_isr(const struct device *dev, + uint8_t updated_flag) +{ + ARG_UNUSED(dev); + /* + * We haven't send callback to system because there is no index 43 + * virtual wire signal is listed in enum espi_vwire_signal. + */ + LOG_INF("vw isr %s is ignored!", __func__); +} + +static void espi_it8xxx2_vwidx44_isr(const struct device *dev, + uint8_t updated_flag) +{ + ARG_UNUSED(dev); + /* + * We haven't send callback to system because there is no index 44 + * virtual wire signal is listed in enum espi_vwire_signal. + */ + LOG_INF("vw isr %s is ignored!", __func__); +} + +static const struct espi_vw_signal_t vwidx47_signals[] = { + {ESPI_VWIRE_SIGNAL_HOST_C10, NULL}, +}; +static void espi_it8xxx2_vwidx47_isr(const struct device *dev, + uint8_t updated_flag) +{ + for (int i = 0; i < ARRAY_SIZE(vwidx47_signals); i++) { + enum espi_vwire_signal vw_signal = vwidx47_signals[i].signal; + + if (updated_flag & vw_channel_list[vw_signal].level_mask) { + espi_it8xxx2_vw_notify_system_state(dev, vw_signal); + } + } +} + +/* + * The ISR of espi VW interrupt in array needs to match bit order in + * ESPI VW VWCTRL1 register. + */ +static const struct vwidx_isr_t vwidx_isr_list[] = { + [0] = {espi_it8xxx2_vwidx2_isr, 0x02}, + [1] = {espi_it8xxx2_vwidx3_isr, 0x03}, + [2] = {espi_it8xxx2_vwidx7_isr, 0x07}, + [3] = {espi_it8xxx2_vwidx41_isr, 0x41}, + [4] = {espi_it8xxx2_vwidx42_isr, 0x42}, + [5] = {espi_it8xxx2_vwidx43_isr, 0x43}, + [6] = {espi_it8xxx2_vwidx44_isr, 0x44}, + [7] = {espi_it8xxx2_vwidx47_isr, 0x47}, +}; + +/* + * This is used to record the previous VW valid/level field state to discover + * changes. Then do following sequence only when state is changed. + */ +static uint8_t vwidx_cached_flag[ARRAY_SIZE(vwidx_isr_list)]; + +static void espi_it8xxx2_reset_vwidx_cache(const struct device *dev) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_vw_regs *const vw_reg = + (struct espi_vw_regs *)config->base_espi_vw; + + /* reset vwidx_cached_flag */ + for (int i = 0; i < ARRAY_SIZE(vwidx_isr_list); i++) { + vwidx_cached_flag[i] = + vw_reg->VW_INDEX[vwidx_isr_list[i].vw_index]; + } +} + +static void espi_it8xxx2_vw_isr(const struct device *dev) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_vw_regs *const vw_reg = + (struct espi_vw_regs *)config->base_espi_vw; + uint8_t vwidx_updated = vw_reg->VWCTRL1; + + /* write-1 to clear */ + vw_reg->VWCTRL1 = vwidx_updated; + + for (int i = 0; i < ARRAY_SIZE(vwidx_isr_list); i++) { + if (vwidx_updated & BIT(i)) { + uint8_t vw_flag; + + vw_flag = vw_reg->VW_INDEX[vwidx_isr_list[i].vw_index]; + vwidx_isr_list[i].vwidx_isr(dev, + vwidx_cached_flag[i] ^ vw_flag); + vwidx_cached_flag[i] = vw_flag; + } + } +} + +static void espi_it8xxx2_ch_notify_system_state(const struct device *dev, + enum espi_channel ch, bool en) +{ + struct espi_it8xxx2_data *const data = DRV_DATA(dev); + struct espi_event evt = { + .evt_type = ESPI_BUS_EVENT_CHANNEL_READY, + .evt_details = ch, + .evt_data = en, + }; + + espi_send_callbacks(&data->callbacks, dev, evt); +} + +/* + * Peripheral channel enable asserted flag. + * A 0-to-1 or 1-to-0 transition on "Peripheral Channel Enable" bit. + */ +static void espi_it8xxx2_peripheral_ch_en_isr(const struct device *dev, + bool enable) +{ + espi_it8xxx2_ch_notify_system_state(dev, + ESPI_CHANNEL_PERIPHERAL, enable); +} + +/* + * VW channel enable asserted flag. + * A 0-to-1 or 1-to-0 transition on "Virtual Wire Channel Enable" bit. + */ +static void espi_it8xxx2_vw_ch_en_isr(const struct device *dev, bool enable) +{ + if (enable) { + espi_vw_set_valid(dev, ESPI_VWIRE_SIGNAL_SUS_ACK, 1); + } + + espi_it8xxx2_ch_notify_system_state(dev, ESPI_CHANNEL_VWIRE, enable); +} + +/* + * OOB message channel enable asserted flag. + * A 0-to-1 or 1-to-0 transition on "OOB Message Channel Enable" bit. + */ +static void espi_it8xxx2_oob_ch_en_isr(const struct device *dev, bool enable) +{ + if (enable) { + espi_vw_set_valid(dev, ESPI_VWIRE_SIGNAL_OOB_RST_ACK, 1); + } + + espi_it8xxx2_ch_notify_system_state(dev, ESPI_CHANNEL_OOB, enable); +} + +/* + * Flash channel enable asserted flag. + * A 0-to-1 or 1-to-0 transition on "Flash Access Channel Enable" bit. + */ +static void espi_it8xxx2_flash_ch_en_isr(const struct device *dev, bool enable) +{ + if (enable) { + espi_vw_set_valid(dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_STS, 1); + espi_vw_set_valid(dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, 1); + espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_STS, 1); + espi_it8xxx2_send_vwire(dev, + ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, 1); + } + + espi_it8xxx2_ch_notify_system_state(dev, ESPI_CHANNEL_FLASH, enable); +} + +static void espi_it8xxx2_put_pc_status_isr(const struct device *dev) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_slave_regs *const slave_reg = + (struct espi_slave_regs *)config->base_espi_slave; + + /* + * TODO: To check cycle type (bit[3-0] at ESPCTRL0) and make + * corresponding modification if needed. + */ + LOG_INF("isr %s is ignored!", __func__); + + /* write-1-clear to release PC_FREE */ + slave_reg->ESPCTRL0 = IT8XXX2_ESPI_INTERRUPT_PUT_PC; +} + +static void espi_it8xxx2_upstream_channel_disable_isr(const struct device *dev) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_slave_regs *const slave_reg = + (struct espi_slave_regs *)config->base_espi_slave; + + LOG_INF("isr %s is ignored!", __func__); + + /* write-1 to clear this bit */ + slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_CHANNEL_DISABLE; +} + +static void espi_it8xxx2_upstream_done_isr(const struct device *dev) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_slave_regs *const slave_reg = + (struct espi_slave_regs *)config->base_espi_slave; + + LOG_INF("isr %s is ignored!", __func__); + + /* write-1 to clear this bit */ + slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_DONE; +} + +static void espi_it8xxx2_put_oob_status_isr(const struct device *dev) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_slave_regs *const slave_reg = + (struct espi_slave_regs *)config->base_espi_slave; + + LOG_INF("isr %s is ignored!", __func__); + + /* Write-1 to clear this bit for the next coming posted transaction. */ + slave_reg->ESOCTRL0 |= IT8XXX2_ESPI_PUT_OOB_STATUS; +} + +/* + * The ISR of espi interrupt event in array need to be matched bit order in + * IT8XXX2 ESPI ESGCTRL0 register. + */ +static const struct espi_isr_t espi_isr_list[] = { + [0] = {espi_it8xxx2_peripheral_ch_en_isr, ASSERTED_FLAG}, + [1] = {espi_it8xxx2_vw_ch_en_isr, ASSERTED_FLAG}, + [2] = {espi_it8xxx2_oob_ch_en_isr, ASSERTED_FLAG}, + [3] = {espi_it8xxx2_flash_ch_en_isr, ASSERTED_FLAG}, + [4] = {espi_it8xxx2_peripheral_ch_en_isr, DEASSERTED_FLAG}, + [5] = {espi_it8xxx2_vw_ch_en_isr, DEASSERTED_FLAG}, + [6] = {espi_it8xxx2_oob_ch_en_isr, DEASSERTED_FLAG}, + [7] = {espi_it8xxx2_flash_ch_en_isr, DEASSERTED_FLAG}, +}; + +static void espi_it8xxx2_isr(const struct device *dev) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_slave_regs *const slave_reg = + (struct espi_slave_regs *)config->base_espi_slave; + /* get espi interrupt events */ + uint8_t espi_event = slave_reg->ESGCTRL0; + uint8_t espi_upstream = slave_reg->ESUCTRL0; + + /* write-1 to clear */ + slave_reg->ESGCTRL0 = espi_event; + + /* process espi interrupt events */ + for (int i = 0; i < ARRAY_SIZE(espi_isr_list); i++) { + if (espi_event & BIT(i)) { + espi_isr_list[i].espi_isr(dev, + espi_isr_list[i].isr_type); + } + } + + /* + * bit7: the peripheral has received a peripheral posted/completion. + * This bit indicates the peripheral has received a packet from eSPI + * peripheral channel. + */ + if (slave_reg->ESPCTRL0 & IT8XXX2_ESPI_INTERRUPT_PUT_PC) { + espi_it8xxx2_put_pc_status_isr(dev); + } + + /* + * The corresponding channel of the eSPI upstream transaction is + * disabled. + */ + if (espi_upstream & IT8XXX2_ESPI_UPSTREAM_CHANNEL_DISABLE) { + espi_it8xxx2_upstream_channel_disable_isr(dev); + } + + /* The eSPI upstream transaction is done. */ + if (espi_upstream & IT8XXX2_ESPI_UPSTREAM_DONE) { + espi_it8xxx2_upstream_done_isr(dev); + } + + /* The eSPI slave has received a PUT_OOB message. */ + if (slave_reg->ESOCTRL0 & IT8XXX2_ESPI_PUT_OOB_STATUS) { + espi_it8xxx2_put_oob_status_isr(dev); + } +} + +void espi_it8xxx2_enable_pad_ctrl(const struct device *dev, bool enable) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_slave_regs *const slave_reg = + (struct espi_slave_regs *)config->base_espi_slave; + + if (enable) { + /* Enable eSPI pad. */ + slave_reg->ESGCTRL2 &= ~IT8XXX2_ESPI_INPUT_PAD_GATING; + } else { + /* Disable eSPI pad. */ + slave_reg->ESGCTRL2 |= IT8XXX2_ESPI_INPUT_PAD_GATING; + } +} + +void espi_it8xxx2_espi_reset_isr(const struct device *port, + struct gpio_callback *cb, uint32_t pins) +{ + struct espi_it8xxx2_data *const data = DRV_DATA(ESPI_IT8XXX2_SOC_DEV); + struct espi_event evt = {ESPI_BUS_RESET, 0, 0}; + bool espi_reset = gpio_pin_get(port, (find_msb_set(pins) - 1)); + + if (!(espi_reset)) { + /* Reset vwidx_cached_flag[] when espi_reset# asserted. */ + espi_it8xxx2_reset_vwidx_cache(ESPI_IT8XXX2_SOC_DEV); + } + + evt.evt_data = espi_reset; + espi_send_callbacks(&data->callbacks, ESPI_IT8XXX2_SOC_DEV, evt); + + LOG_INF("eSPI reset %sasserted", espi_reset ? "de" : ""); +} + +/* eSPI reset# is enabled on GPD2 */ +#define ESPI_IT8XXX2_ESPI_RESET_PORT DEVICE_DT_GET(DT_NODELABEL(gpiod)) +#define ESPI_IT8XXX2_ESPI_RESET_PIN 2 +static void espi_it8xxx2_enable_reset(void) +{ + static struct gpio_callback espi_reset_cb; + + /* eSPI reset is enabled on GPD2 */ + IT8XXX2_GPIO_GCR = + (IT8XXX2_GPIO_GCR & ~IT8XXX2_GPIO_GCR_ESPI_RST_EN_MASK) | + (IT8XXX2_GPIO_GCR_ESPI_RST_D2 << IT8XXX2_GPIO_GCR_ESPI_RST_POS); + /* enable eSPI reset isr */ + gpio_init_callback(&espi_reset_cb, espi_it8xxx2_espi_reset_isr, + BIT(ESPI_IT8XXX2_ESPI_RESET_PIN)); + gpio_add_callback(ESPI_IT8XXX2_ESPI_RESET_PORT, &espi_reset_cb); + gpio_pin_interrupt_configure(ESPI_IT8XXX2_ESPI_RESET_PORT, + ESPI_IT8XXX2_ESPI_RESET_PIN, + GPIO_INT_TRIG_BOTH); +} + +static struct espi_it8xxx2_data espi_it8xxx2_data_0; +static const struct espi_it8xxx2_config espi_it8xxx2_config_0 = { + .base_espi_slave = DT_INST_REG_ADDR_BY_IDX(0, 0), + .base_espi_vw = DT_INST_REG_ADDR_BY_IDX(0, 1), + .base_espi_queue1 = DT_INST_REG_ADDR_BY_IDX(0, 2), + .base_espi_queue0 = DT_INST_REG_ADDR_BY_IDX(0, 3), + .base_ec2i = DT_INST_REG_ADDR_BY_IDX(0, 4), + .base_kbc = DT_INST_REG_ADDR_BY_IDX(0, 5), + .base_pmc = DT_INST_REG_ADDR_BY_IDX(0, 6), +}; + +DEVICE_DT_INST_DEFINE(0, &espi_it8xxx2_init, NULL, + &espi_it8xxx2_data_0, &espi_it8xxx2_config_0, + PRE_KERNEL_2, CONFIG_ESPI_INIT_PRIORITY, + &espi_it8xxx2_driver_api); + +static int espi_it8xxx2_init(const struct device *dev) +{ + const struct espi_it8xxx2_config *const config = DRV_CONFIG(dev); + struct espi_vw_regs *const vw_reg = + (struct espi_vw_regs *)config->base_espi_vw; + struct espi_slave_regs *const slave_reg = + (struct espi_slave_regs *)config->base_espi_slave; + struct gctrl_it8xxx2_regs *const gctrl = ESPI_IT8XXX2_GET_GCTRL_BASE; + + /* configure VCC detector */ + gctrl->GCTRL_RSTS = (gctrl->GCTRL_RSTS & + ~(IT8XXX2_GCTRL_VCCDO_MASK | IT8XXX2_GCTRL_HGRST)) | + (IT8XXX2_GCTRL_VCCDO_VCC_ON | IT8XXX2_GCTRL_GRST); + + /* enable PNPCFG devices */ + pnpcfg_it8xxx2_init(dev); + +#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC + /* enable kbc port (60h/64h) */ + kbc_it8xxx2_init(dev); +#endif +#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO + /* enable pmc1 for ACPI port (62h/66h) */ + pmc1_it8xxx2_init(dev); +#endif +#ifdef CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80 + /* Accept Port 80h Cycle */ + port80_it8xxx2_init(dev); +#endif + + /* Reset vwidx_cached_flag[] at initialization */ + espi_it8xxx2_reset_vwidx_cache(dev); + + /* Enable espi vw interrupt */ + vw_reg->VWCTRL0 |= IT8XXX2_ESPI_VW_INTERRUPT_ENABLE; + IRQ_CONNECT(IT8XXX2_ESPI_VW_IRQ, 0, espi_it8xxx2_vw_isr, + DEVICE_DT_INST_GET(0), 0); + irq_enable(IT8XXX2_ESPI_VW_IRQ); + + /* Upstream interrupt enable */ + slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_INTERRUPT_ENABLE; + + /* PUT_OOB interrupt enable */ + slave_reg->ESOCTRL1 |= IT8XXX2_ESPI_PUT_OOB_INTERRUPT_ENABLE; + + /* Enable espi interrupt */ + slave_reg->ESGCTRL1 |= IT8XXX2_ESPI_INTERRUPT_ENABLE; + IRQ_CONNECT(IT8XXX2_ESPI_IRQ, 0, espi_it8xxx2_isr, + DEVICE_DT_INST_GET(0), 0); + irq_enable(IT8XXX2_ESPI_IRQ); + + /* enable interrupt and reset from eSPI_reset# */ + espi_it8xxx2_enable_reset(); + + /* + * Enable eSPI to WUC. + * If an eSPI transaction is accepted, WU42 interrupt will be asserted. + */ + slave_reg->ESGCTRL2 |= IT8XXX2_ESPI_TO_WUC_ENABLE; + + /* TODO: enable WU42 of WUI */ + + return 0; +} diff --git a/dts/riscv/it8xxx2.dtsi b/dts/riscv/it8xxx2.dtsi index 53bba4ed58d..c1b0192849c 100644 --- a/dts/riscv/it8xxx2.dtsi +++ b/dts/riscv/it8xxx2.dtsi @@ -571,6 +571,28 @@ #gpio-cells = <2>; }; + espi0: espi@f03100 { + compatible = "ite,it8xxx2-espi"; + reg = <0x00f03100 0xd8 /* eSPI slave */ + 0x00f03200 0x9a /* eSPI VW */ + 0x00f03300 0xd0 /* eSPI Queue 0 */ + 0x00f03400 0xc0 /* eSPI Queue 1 */ + 0x00f01200 6 /* EC2I bridge */ + 0x00f01300 11 /* Host KBC */ + 0x00f01500 0x100>; /* Host PMC */ + interrupts = ; + interrupt-parent = <&intc>; + label = "ESPI_0"; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + }; + spi0:spi@f02600 { #address-cells = <1>; #size-cells = <0>; diff --git a/include/dt-bindings/interrupt-controller/ite-intc.h b/include/dt-bindings/interrupt-controller/ite-intc.h index af2aa47d2ae..3c062199947 100644 --- a/include/dt-bindings/interrupt-controller/ite-intc.h +++ b/include/dt-bindings/interrupt-controller/ite-intc.h @@ -16,6 +16,7 @@ /* IRQ numbers of WUC */ /* Group 0 of INTC */ #define IT8XXX2_IRQ_WU20 1 +#define IT8XXX2_IRQ_KBC_OBE 2 #define IT8XXX2_IRQ_WU23 6 /* Group 1 */ #define IT8XXX2_IRQ_WU26 12 @@ -25,6 +26,8 @@ #define IT8XXX2_IRQ_WU24 17 #define IT8XXX2_IRQ_WU22 21 /* Group 3 */ +#define IT8XXX2_IRQ_KBC_IBF 24 +#define IT8XXX2_IRQ_PMC1_IBF 25 #define IT8XXX2_IRQ_TIMER1 30 #define IT8XXX2_IRQ_WU21 31 /* Group 5 */ @@ -136,6 +139,9 @@ #define IT8XXX2_IRQ_TIMER6 158 #define IT8XXX2_IRQ_TIMER7 159 /* Group 20 */ +#define IT8XXX2_IRQ_ESPI 162 +#define IT8XXX2_IRQ_ESPI_VW 163 +#define IT8XXX2_IRQ_PCH_P80 164 #define IT8XXX2_IRQ_USBPD0 165 #define IT8XXX2_IRQ_USBPD1 166 /* Group 21 */ diff --git a/soc/riscv/riscv-ite/common/check_regs.c b/soc/riscv/riscv-ite/common/check_regs.c index dc27b4db610..b44b5a31479 100644 --- a/soc/riscv/riscv-ite/common/check_regs.c +++ b/soc/riscv/riscv-ite/common/check_regs.c @@ -7,12 +7,66 @@ #include #include +/* EC2I register structure check */ +IT8XXX2_REG_SIZE_CHECK(ec2i_regs, 0x06); +IT8XXX2_REG_OFFSET_CHECK(ec2i_regs, IHIOA, 0x00); +IT8XXX2_REG_OFFSET_CHECK(ec2i_regs, IHD, 0x01); +IT8XXX2_REG_OFFSET_CHECK(ec2i_regs, LSIOHA, 0x02); +IT8XXX2_REG_OFFSET_CHECK(ec2i_regs, IBMAE, 0x04); +IT8XXX2_REG_OFFSET_CHECK(ec2i_regs, IBCTL, 0x05); + +/* KBC register structure check */ +IT8XXX2_REG_SIZE_CHECK(kbc_regs, 0x0b); +IT8XXX2_REG_OFFSET_CHECK(kbc_regs, KBHICR, 0x00); +IT8XXX2_REG_OFFSET_CHECK(kbc_regs, KBIRQR, 0x02); +IT8XXX2_REG_OFFSET_CHECK(kbc_regs, KBHISR, 0x04); +IT8XXX2_REG_OFFSET_CHECK(kbc_regs, KBHIKDOR, 0x06); +IT8XXX2_REG_OFFSET_CHECK(kbc_regs, KBHIMDOR, 0x08); +IT8XXX2_REG_OFFSET_CHECK(kbc_regs, KBHIDIR, 0x0a); + +/* PMC register structure check */ +IT8XXX2_REG_SIZE_CHECK(pmc_regs, 0x100); +IT8XXX2_REG_OFFSET_CHECK(pmc_regs, PM1STS, 0x00); +IT8XXX2_REG_OFFSET_CHECK(pmc_regs, PM1DO, 0x01); +IT8XXX2_REG_OFFSET_CHECK(pmc_regs, PM1DI, 0x04); +IT8XXX2_REG_OFFSET_CHECK(pmc_regs, PM1CTL, 0x06); + +/* eSPI slave register structure check */ +IT8XXX2_REG_SIZE_CHECK(espi_slave_regs, 0xd8); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, GCAPCFG1, 0x05); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, CH_PC_CAPCFG3, 0x0b); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, CH_VW_CAPCFG3, 0x0f); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, CH_OOB_CAPCFG3, 0x13); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, CH_FLASH_CAPCFG3, 0x17); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, CH_FLASH_CAPCFG2_3, 0x1b); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, ESPCTRL0, 0x90); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, ESGCTRL0, 0xa0); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, ESGCTRL1, 0xa1); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, ESGCTRL2, 0xa2); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, ESUCTRL0, 0xb0); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, ESOCTRL0, 0xc0); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, ESOCTRL1, 0xc1); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, ESPISAFSC0, 0xd0); +IT8XXX2_REG_OFFSET_CHECK(espi_slave_regs, ESPISAFSC7, 0xd7); + +/* eSPI vw register structure check */ +IT8XXX2_REG_SIZE_CHECK(espi_vw_regs, 0x9a); +IT8XXX2_REG_OFFSET_CHECK(espi_vw_regs, VW_INDEX, 0x00); +IT8XXX2_REG_OFFSET_CHECK(espi_vw_regs, VWCTRL0, 0x90); +IT8XXX2_REG_OFFSET_CHECK(espi_vw_regs, VWCTRL1, 0x91); + /* GCTRL register structure check */ IT8XXX2_REG_SIZE_CHECK(gctrl_it8xxx2_regs, 0x88); IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_RSTS, 0x06); +IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_BADRSEL, 0x0a); +IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_WNCKR, 0x0b); +IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_SPCTRL1, 0x0d); IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_SPCTRL4, 0x1c); IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_RSTC5, 0x21); IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_MCCR2, 0x44); +IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_P80H81HSR, 0x50); +IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_P80HDR, 0x51); +IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_H2ROFSR, 0x53); IT8XXX2_REG_OFFSET_CHECK(gctrl_it8xxx2_regs, GCTRL_ECHIPID2, 0x86); /* KSCAN register structure check */ diff --git a/soc/riscv/riscv-ite/common/chip_chipregs.h b/soc/riscv/riscv-ite/common/chip_chipregs.h index f1d599e2540..b6bb47a4a8a 100644 --- a/soc/riscv/riscv-ite/common/chip_chipregs.h +++ b/soc/riscv/riscv-ite/common/chip_chipregs.h @@ -403,70 +403,6 @@ #define IVECT ECREG(EC_REG_BASE_ADDR + 0x3F10) -/** - * - * (12xxh) EC Access to ost Controlled Modules (EC2I Bridge) - * - */ -#define IHIOA ECREG(EC_REG_BASE_ADDR + 0x1200) -#define IHD ECREG(EC_REG_BASE_ADDR + 0x1201) -#define LSIOHA ECREG(EC_REG_BASE_ADDR + 0x1202) -#define SIOLV ECREG(EC_REG_BASE_ADDR + 0x1203) -#define IBMAE ECREG(EC_REG_BASE_ADDR + 0x1204) -#define IBCTL ECREG(EC_REG_BASE_ADDR + 0x1205) - -/* Lock Super I/O Host Access Register */ -#define LKCFG BIT(0) - -/* Super I/O Access Lock Violation Register */ -#define CFGLV BIT(0) - -/* EC to I-Bus Modules Access Enable Register */ -#define SWUCAE BIT(2) -#define CFGAE BIT(0) - -/* I-Bus Control Register */ -#define CWIB BIT(2) -#define CRIB BIT(1) -#define CSAE BIT(0) - -/** - * - * (13xxh) Keyboard Controller (KBC) - * - */ -#define KBHICR ECREG(EC_REG_BASE_ADDR + 0x1300) -#define KBIRQR ECREG(EC_REG_BASE_ADDR + 0x1302) -#define KBHISR ECREG(EC_REG_BASE_ADDR + 0x1304) -#define KBHIKDOR ECREG(EC_REG_BASE_ADDR + 0x1306) -#define KBHIMDOR ECREG(EC_REG_BASE_ADDR + 0x1308) -#define KBHIDIR ECREG(EC_REG_BASE_ADDR + 0x130A) - -/* KBC Host Interface Control Register*/ -#define PM1ICIE BIT(6) -#define PM1OCIE BIT(5) -#define PM1HIE BIT(4) -#define IBFCIE BIT(3) -#define OBECIE BIT(2) -#define OBFMIE BIT(1) -#define OBFKIE BIT(0) - -/* KBC Interrupt Control Register */ -#define IRQNP BIT(6) -#define IRQ11B BIT(2) -#define IRQ12B BIT(1) -#define IRQ1B BIT(0) - -/* KBC Host Interface Keyboard/Mouse Status Register */ -#define PARE BIT(7) -#define GTIM BIT(6) -#define AOBF BIT(5) -#define KEYL BIT(4) -#define C_D BIT(3) -#define SYSF BIT(2) -#define IBF BIT(1) -#define OBF BIT(0) - /** * * (14xxh) System Wake-Up Control (SWUC) @@ -524,100 +460,6 @@ #define PRC0R ECREG(EC_REG_BASE_ADDR + 0x141C) #define PRC1R ECREG(EC_REG_BASE_ADDR + 0x141D) -/** - * - * (15xxh) Power Management Channel (PMC) - * - */ -/* PM1 */ -#define PM1STS ECREG(EC_REG_BASE_ADDR + 0x1500) -#define PM1DO ECREG(EC_REG_BASE_ADDR + 0x1501) -#define PM1DOSCI ECREG(EC_REG_BASE_ADDR + 0x1502) -#define PM1DOSMI ECREG(EC_REG_BASE_ADDR + 0x1503) -#define PM1DI ECREG(EC_REG_BASE_ADDR + 0x1504) -#define PM1DISCI ECREG(EC_REG_BASE_ADDR + 0x1505) -#define PM1CTL ECREG(EC_REG_BASE_ADDR + 0x1506) -#define PM1IC ECREG(EC_REG_BASE_ADDR + 0x1507) -#define PM1IE ECREG(EC_REG_BASE_ADDR + 0x1508) -/* PM2 */ -#define PM2STS ECREG(EC_REG_BASE_ADDR + 0x1510) -#define PM2DO ECREG(EC_REG_BASE_ADDR + 0x1511) -#define PM2DOSCI ECREG(EC_REG_BASE_ADDR + 0x1512) -#define PM2DOSMI ECREG(EC_REG_BASE_ADDR + 0x1513) -#define PM2DI ECREG(EC_REG_BASE_ADDR + 0x1514) -#define PM2DISCI ECREG(EC_REG_BASE_ADDR + 0x1515) -#define PM2CTL ECREG(EC_REG_BASE_ADDR + 0x1516) -#define PM2IC ECREG(EC_REG_BASE_ADDR + 0x1517) -#define PM2IE ECREG(EC_REG_BASE_ADDR + 0x1518) -/* Mailbox */ -#define MBXCTRL ECREG(EC_REG_BASE_ADDR + 0x1519) -/* 16-byte PMC2EX Mailbox 0 ~ Mailbox 15 */ -#define MBXEC_00 ECREG(EC_REG_BASE_ADDR + 0x15F0) -#define MBXEC_01 ECREG(EC_REG_BASE_ADDR + 0x15F1) -#define MBXEC_02 ECREG(EC_REG_BASE_ADDR + 0x15F2) -#define MBXEC_03 ECREG(EC_REG_BASE_ADDR + 0x15F3) -#define MBXEC_04 ECREG(EC_REG_BASE_ADDR + 0x15F4) -#define MBXEC_05 ECREG(EC_REG_BASE_ADDR + 0x15F5) -#define MBXEC_06 ECREG(EC_REG_BASE_ADDR + 0x15F6) -#define MBXEC_07 ECREG(EC_REG_BASE_ADDR + 0x15F7) -#define MBXEC_08 ECREG(EC_REG_BASE_ADDR + 0x15F8) -#define MBXEC_09 ECREG(EC_REG_BASE_ADDR + 0x15F9) -#define MBXEC_10 ECREG(EC_REG_BASE_ADDR + 0x15FA) -#define MBXEC_11 ECREG(EC_REG_BASE_ADDR + 0x15FB) -#define MBXEC_12 ECREG(EC_REG_BASE_ADDR + 0x15FC) -#define MBXEC_13 ECREG(EC_REG_BASE_ADDR + 0x15FD) -#define MBXEC_14 ECREG(EC_REG_BASE_ADDR + 0x15FE) -#define MBXEC_15 ECREG(EC_REG_BASE_ADDR + 0x15FF) -#define PM3STS ECREG(EC_REG_BASE_ADDR + 0x1520) -#define PM3DO ECREG(EC_REG_BASE_ADDR + 0x1521) -#define PM3DI ECREG(EC_REG_BASE_ADDR + 0x1522) -#define PM3CTL ECREG(EC_REG_BASE_ADDR + 0x1523) -#define PM3IC ECREG(EC_REG_BASE_ADDR + 0x1524) -#define PM3IE ECREG(EC_REG_BASE_ADDR + 0x1525) -#define PM4STS ECREG(EC_REG_BASE_ADDR + 0x1530) -#define PM4DO ECREG(EC_REG_BASE_ADDR + 0x1531) -#define PM4DI ECREG(EC_REG_BASE_ADDR + 0x1532) -#define PM4CTL ECREG(EC_REG_BASE_ADDR + 0x1533) -#define PM4IC ECREG(EC_REG_BASE_ADDR + 0x1534) -#define PM4IE ECREG(EC_REG_BASE_ADDR + 0x1535) -#define PM5STS ECREG(EC_REG_BASE_ADDR + 0x1540) -#define PM5DO ECREG(EC_REG_BASE_ADDR + 0x1541) -#define PM5DI ECREG(EC_REG_BASE_ADDR + 0x1542) -#define PM5CTL ECREG(EC_REG_BASE_ADDR + 0x1543) -#define PM5IC ECREG(EC_REG_BASE_ADDR + 0x1544) -#define PM5IE ECREG(EC_REG_BASE_ADDR + 0x1545) - -/* PM Status Register */ -#define SMIEVT BIT(6) -#define SCIEVT BIT(5) -#define BURST BIT(4) -#define P_C_D BIT(3) -#define P_IBF BIT(1) -#define P_OBF BIT(0) - -/* PM Control */ -#define APM BIT(7) -#define SCINP BIT(6) -#define OBEIE BIT(1) -#define IBFIE BIT(0) - -/* PM Interrupt Control */ -#define SMINP BIT(6) -#define SCIB BIT(2) -#define SMIB BIT(1) -#define IRQB BIT(0) - -/* PM Interrupt Enable */ -#define HWSMIEN BIT(5) -#define HWSCIEN BIT(4) -#define HWIRQEN BIT(3) -#define SMIEN BIT(2) -#define SCIEN BIT(1) -#define IRQEN BIT(0) - -/* PM Interrupt Enable */ -#define MBXEN BIT(7) - /** * * (16XXh) General Purpose I/O Control Register @@ -1677,7 +1519,11 @@ struct flash_it8xxx2_regs { #define IT8XXX2_GPIO_BASE 0x00F01600 #define IT8XXX2_GPIO2_BASE 0x00F03E00 +/* TODO: create interface for accessing GPIO general control registers. */ #define IT8XXX2_GPIO_GCR ECREG(IT8XXX2_GPIO_BASE + 0x00) +#define IT8XXX2_GPIO_GCR_ESPI_RST_D2 0x2 +#define IT8XXX2_GPIO_GCR_ESPI_RST_POS 1 +#define IT8XXX2_GPIO_GCR_ESPI_RST_EN_MASK (0x3 << IT8XXX2_GPIO_GCR_ESPI_RST_POS) #define IT8XXX2_GPIO_GCRX(offset) ECREG(IT8XXX2_GPIO_BASE + (offset)) #define IT8XXX2_GPIO_GCR25_OFFSET 0xd1 @@ -1949,8 +1795,18 @@ struct gctrl_it8xxx2_regs { volatile uint8_t reserved2[3]; /* 0x06: Reset Status */ volatile uint8_t GCTRL_RSTS; - /* 0x07-0x1B: Reserved3 */ - volatile uint8_t reserved3[21]; + /* 0x07-0x09: Reserved3 */ + volatile uint8_t reserved3[3]; + /* 0x0a: Base Address Select */ + volatile uint8_t GCTRL_BADRSEL; + /* 0x0b: Wait Next Clock Rising */ + volatile uint8_t GCTRL_WNCKR; + /* 0x0c: Reserved3-1 */ + volatile uint8_t reserved3_1; + /* 0x0d: Special Control 1 */ + volatile uint8_t GCTRL_SPCTRL1; + /* 0x0E-0x1B: Reserved3-2 */ + volatile uint8_t reserved3_2[14]; /* 0x1C: Special Control 4 */ volatile uint8_t GCTRL_SPCTRL4; /* 0x1D-0x1F: Reserved4 */ @@ -1987,8 +1843,18 @@ struct gctrl_it8xxx2_regs { volatile uint8_t GCTRL_ETWDUARTCR; /* 0x4C: Wakeup MCU Control */ volatile uint8_t GCTRL_WMCR; - /* 0x4D-0x84: Reserved11 */ - volatile uint8_t reserved11[56]; + /* 0x4D-0x4F: Reserved11 */ + volatile uint8_t reserved11[3]; + /* 0x50: Port 80h/81h Status Register */ + volatile uint8_t GCTRL_P80H81HSR; + /* 0x51: Port 80h Data Register */ + volatile uint8_t GCTRL_P80HDR; + /* 0x52: Port 81h Data Register */ + volatile uint8_t GCTRL_P81HDR; + /* 0x53: H2RAM Offset Register */ + volatile uint8_t GCTRL_H2ROFSR; + /* 0x54-0x84: Reserved11-1 */ + volatile uint8_t reserved11_1[49]; /* 0x85: Chip ID Byte 1 */ volatile uint8_t GCTRL_ECHIPID1; /* 0x86: Chip ID Byte 2 */ @@ -2008,5 +1874,423 @@ struct gctrl_it8xxx2_regs { #define IT8XXX2_GCTRL_LRSIPGWR BIT(0) /* 0x4B: ETWD and UART Control */ #define IT8XXX2_GCTRL_ETWD_HW_RST_EN BIT(0) +/* Accept Port 80h Cycle */ +#define IT8XXX2_GCTRL_ACP80 BIT(6) + +/* + * VCC Detector Option. + * bit[7-6] = 1: The VCC power status is treated as power-on. + * The VCC supply of eSPI and related functions (EC2I, KBC, PMC and + * PECI). It means VCC should be logic high before using these + * functions, or firmware treats VCC logic high. + */ +#define IT8XXX2_GCTRL_VCCDO_MASK (BIT(6) | BIT(7)) +#define IT8XXX2_GCTRL_VCCDO_VCC_ON BIT(6) +/* + * bit[3] = 0: The reset source of PNPCFG is RSTPNP bit in RSTCH + * register and WRST#. + */ +#define IT8XXX2_GCTRL_HGRST BIT(3) +/* bit[2] = 1: Enable global reset. */ +#define IT8XXX2_GCTRL_GRST BIT(2) + +#ifndef __ASSEMBLER__ +/* + * EC2I bridge registers + */ +struct ec2i_regs { + /* 0x00: Indirect Host I/O Address Register */ + volatile uint8_t IHIOA; + /* 0x01: Indirect Host Data Register */ + volatile uint8_t IHD; + /* 0x02: Lock Super I/O Host Access Register */ + volatile uint8_t LSIOHA; + /* 0x03: Super I/O Access Lock Violation Register */ + volatile uint8_t SIOLV; + /* 0x04: EC to I-Bus Modules Access Enable Register */ + volatile uint8_t IBMAE; + /* 0x05: I-Bus Control Register */ + volatile uint8_t IBCTL; +}; + +/* Index list of the host interface registers of PNPCFG */ +enum host_pnpcfg_index { + /* Logical Device Number */ + HOST_INDEX_LDN = 0x07, + /* Chip ID Byte 1 */ + HOST_INDEX_CHIPID1 = 0x20, + /* Chip ID Byte 2 */ + HOST_INDEX_CHIPID2 = 0x21, + /* Chip Version */ + HOST_INDEX_CHIPVER = 0x22, + /* Super I/O Control */ + HOST_INDEX_SIOCTRL = 0x23, + /* Super I/O IRQ Configuration */ + HOST_INDEX_SIOIRQ = 0x25, + /* Super I/O General Purpose */ + HOST_INDEX_SIOGP = 0x26, + /* Super I/O Power Mode */ + HOST_INDEX_SIOPWR = 0x2D, + /* Depth 2 I/O Address */ + HOST_INDEX_D2ADR = 0x2E, + /* Depth 2 I/O Data */ + HOST_INDEX_D2DAT = 0x2F, + /* Logical Device Activate Register */ + HOST_INDEX_LDA = 0x30, + /* I/O Port Base Address Bits [15:8] for Descriptor 0 */ + HOST_INDEX_IOBAD0_MSB = 0x60, + /* I/O Port Base Address Bits [7:0] for Descriptor 0 */ + HOST_INDEX_IOBAD0_LSB = 0x61, + /* I/O Port Base Address Bits [15:8] for Descriptor 1 */ + HOST_INDEX_IOBAD1_MSB = 0x62, + /* I/O Port Base Address Bits [7:0] for Descriptor 1 */ + HOST_INDEX_IOBAD1_LSB = 0x63, + /* Interrupt Request Number and Wake-Up on IRQ Enabled */ + HOST_INDEX_IRQNUMX = 0x70, + /* Interrupt Request Type Select */ + HOST_INDEX_IRQTP = 0x71, + /* DMA Channel Select 0 */ + HOST_INDEX_DMAS0 = 0x74, + /* DMA Channel Select 1 */ + HOST_INDEX_DMAS1 = 0x75, + /* Device Specific Logical Device Configuration 1 to 10 */ + HOST_INDEX_DSLDC1 = 0xF0, + HOST_INDEX_DSLDC2 = 0xF1, + HOST_INDEX_DSLDC3 = 0xF2, + HOST_INDEX_DSLDC4 = 0xF3, + HOST_INDEX_DSLDC5 = 0xF4, + HOST_INDEX_DSLDC6 = 0xF5, + HOST_INDEX_DSLDC7 = 0xF6, + HOST_INDEX_DSLDC8 = 0xF7, + HOST_INDEX_DSLDC9 = 0xF8, + HOST_INDEX_DSLDC10 = 0xF9, +}; + +/* List of logical device number (LDN) assignments */ +enum logical_device_number { + /* Serial Port 1 */ + LDN_UART1 = 0x01, + /* Serial Port 2 */ + LDN_UART2 = 0x02, + /* System Wake-Up Control */ + LDN_SWUC = 0x04, + /* KBC/Mouse Interface */ + LDN_KBC_MOUSE = 0x05, + /* KBC/Keyboard Interface */ + LDN_KBC_KEYBOARD = 0x06, + /* Consumer IR */ + LDN_CIR = 0x0A, + /* Shared Memory/Flash Interface */ + LDN_SMFI = 0x0F, + /* RTC-like Timer */ + LDN_RTCT = 0x10, + /* Power Management I/F Channel 1 */ + LDN_PMC1 = 0x11, + /* Power Management I/F Channel 2 */ + LDN_PMC2 = 0x12, + /* Serial Peripheral Interface */ + LDN_SSPI = 0x13, + /* Platform Environment Control Interface */ + LDN_PECI = 0x14, + /* Power Management I/F Channel 3 */ + LDN_PMC3 = 0x17, + /* Power Management I/F Channel 4 */ + LDN_PMC4 = 0x18, + /* Power Management I/F Channel 5 */ + LDN_PMC5 = 0x19, +}; + +/* Structure for initializing PNPCFG via ec2i. */ +struct ec2i_t { + /* index port */ + enum host_pnpcfg_index index_port; + /* data port */ + uint8_t data_port; +}; + +/* EC2I access index/data port */ +enum ec2i_access { + /* index port */ + EC2I_ACCESS_INDEX = 0, + /* data port */ + EC2I_ACCESS_DATA = 1, +}; + +/* EC to I-Bus Access Enabled */ +#define EC2I_IBCTL_CSAE BIT(0) +/* EC Read from I-Bus */ +#define EC2I_IBCTL_CRIB BIT(1) +/* EC Write to I-Bus */ +#define EC2I_IBCTL_CWIB BIT(2) +#define EC2I_IBCTL_CRWIB (EC2I_IBCTL_CRIB | EC2I_IBCTL_CWIB) + +/* PNPCFG Register EC Access Enable */ +#define EC2I_IBMAE_CFGAE BIT(0) + +/* + * KBC registers + */ +struct kbc_regs { + /* 0x00: KBC Host Interface Control Register */ + volatile uint8_t KBHICR; + /* 0x01: Reserved1 */ + volatile uint8_t reserved1; + /* 0x02: KBC Interrupt Control Register */ + volatile uint8_t KBIRQR; + /* 0x03: Reserved2 */ + volatile uint8_t reserved2; + /* 0x04: KBC Host Interface Keyboard/Mouse Status Register */ + volatile uint8_t KBHISR; + /* 0x05: Reserved3 */ + volatile uint8_t reserved3; + /* 0x06: KBC Host Interface Keyboard Data Output Register */ + volatile uint8_t KBHIKDOR; + /* 0x07: Reserved4 */ + volatile uint8_t reserved4; + /* 0x08: KBC Host Interface Mouse Data Output Register */ + volatile uint8_t KBHIMDOR; + /* 0x09: Reserved5 */ + volatile uint8_t reserved5; + /* 0x0a: KBC Host Interface Keyboard/Mouse Data Input Register */ + volatile uint8_t KBHIDIR; +}; + +/* Output Buffer Full */ +#define KBC_KBHISR_OBF BIT(0) +/* Input Buffer Full */ +#define KBC_KBHISR_IBF BIT(1) +/* A2 Address (A2) */ +#define KBC_KBHISR_A2_ADDR BIT(3) +#define KBC_KBHISR_STS_MASK (KBC_KBHISR_OBF | KBC_KBHISR_IBF \ + | KBC_KBHISR_A2_ADDR) + +/* Clear Output Buffer Full */ +#define KBC_KBHICR_COBF BIT(6) +/* IBF/OBF Clear Mode Enable */ +#define KBC_KBHICR_IBFOBFCME BIT(5) +/* Input Buffer Full CPU Interrupt Enable */ +#define KBC_KBHICR_IBFCIE BIT(3) +/* Output Buffer Empty CPU Interrupt Enable */ +#define KBC_KBHICR_OBECIE BIT(2) +/* Output Buffer Full Mouse Interrupt Enable */ +#define KBC_KBHICR_OBFMIE BIT(1) +/* Output Buffer Full Keyboard Interrupt Enable */ +#define KBC_KBHICR_OBFKIE BIT(0) + +/* + * PMC registers + */ +struct pmc_regs { + /* 0x00: Host Interface PM Channel 1 Status */ + volatile uint8_t PM1STS; + /* 0x01: Host Interface PM Channel 1 Data Out Port */ + volatile uint8_t PM1DO; + /* 0x02: Host Interface PM Channel 1 Data Out Port with SCI# */ + volatile uint8_t PM1DOSCI; + /* 0x03: Host Interface PM Channel 1 Data Out Port with SMI# */ + volatile uint8_t PM1DOSMI; + /* 0x04: Host Interface PM Channel 1 Data In Port */ + volatile uint8_t PM1DI; + /* 0x05: Host Interface PM Channel 1 Data In Port with SCI# */ + volatile uint8_t PM1DISCI; + /* 0x06: Host Interface PM Channel 1 Control */ + volatile uint8_t PM1CTL; + /* 0x07: Host Interface PM Channel 1 Interrupt Control */ + volatile uint8_t PM1IC; + /* 0x08: Host Interface PM Channel 1 Interrupt Enable */ + volatile uint8_t PM1IE; + /* 0x09-0x0f: Reserved1 */ + volatile uint8_t reserved1[7]; + /* 0x10-0xff: Reserved2 */ + volatile uint8_t reserved2[0xf0]; +}; + +/* Input Buffer Full Interrupt Enable */ +#define PMC_PM1CTL_IBFIE BIT(0) +/* Output Buffer Full */ +#define PMC_PM1STS_OBF BIT(0) +/* Input Buffer Full */ +#define PMC_PM1STS_IBF BIT(1) +/* General Purpose Flag */ +#define PMC_PM1STS_GPF BIT(2) +/* A2 Address (A2) */ +#define PMC_PM1STS_A2_ADDR BIT(3) + +/* + * eSPI slave registers + */ +struct espi_slave_regs { + /* 0x00-0x03: Reserved1 */ + volatile uint8_t reserved1[4]; + + /* 0x04: General Capabilities and Configuration 0 */ + volatile uint8_t GCAPCFG0; + /* 0x05: General Capabilities and Configuration 1 */ + volatile uint8_t GCAPCFG1; + /* 0x06: General Capabilities and Configuration 2 */ + volatile uint8_t GCAPCFG2; + /* 0x07: General Capabilities and Configuration 3 */ + volatile uint8_t GCAPCFG3; + + /* Channel 0 (Peripheral Channel) Capabilities and Configurations */ + /* 0x08: Channel 0 Capabilities and Configuration 0 */ + volatile uint8_t CH_PC_CAPCFG0; + /* 0x09: Channel 0 Capabilities and Configuration 1 */ + volatile uint8_t CH_PC_CAPCFG1; + /* 0x0A: Channel 0 Capabilities and Configuration 2 */ + volatile uint8_t CH_PC_CAPCFG2; + /* 0x0B: Channel 0 Capabilities and Configuration 3 */ + volatile uint8_t CH_PC_CAPCFG3; + + /* Channel 1 (Virtual Wire Channel) Capabilities and Configurations */ + /* 0x0C: Channel 1 Capabilities and Configuration 0 */ + volatile uint8_t CH_VW_CAPCFG0; + /* 0x0D: Channel 1 Capabilities and Configuration 1 */ + volatile uint8_t CH_VW_CAPCFG1; + /* 0x0E: Channel 1 Capabilities and Configuration 2 */ + volatile uint8_t CH_VW_CAPCFG2; + /* 0x0F: Channel 1 Capabilities and Configuration 3 */ + volatile uint8_t CH_VW_CAPCFG3; + + /* Channel 2 (OOB Message Channel) Capabilities and Configurations */ + /* 0x10: Channel 2 Capabilities and Configuration 0 */ + volatile uint8_t CH_OOB_CAPCFG0; + /* 0x11: Channel 2 Capabilities and Configuration 1 */ + volatile uint8_t CH_OOB_CAPCFG1; + /* 0x12: Channel 2 Capabilities and Configuration 2 */ + volatile uint8_t CH_OOB_CAPCFG2; + /* 0x13: Channel 2 Capabilities and Configuration 3 */ + volatile uint8_t CH_OOB_CAPCFG3; + + /* Channel 3 (Flash Access Channel) Capabilities and Configurations */ + /* 0x14: Channel 3 Capabilities and Configuration 0 */ + volatile uint8_t CH_FLASH_CAPCFG0; + /* 0x15: Channel 3 Capabilities and Configuration 1 */ + volatile uint8_t CH_FLASH_CAPCFG1; + /* 0x16: Channel 3 Capabilities and Configuration 2 */ + volatile uint8_t CH_FLASH_CAPCFG2; + /* 0x17: Channel 3 Capabilities and Configuration 3 */ + volatile uint8_t CH_FLASH_CAPCFG3; + /* Channel 3 Capabilities and Configurations 2 */ + /* 0x18: Channel 3 Capabilities and Configuration 2-0 */ + volatile uint8_t CH_FLASH_CAPCFG2_0; + /* 0x19: Channel 3 Capabilities and Configuration 2-1 */ + volatile uint8_t CH_FLASH_CAPCFG2_1; + /* 0x1A: Channel 3 Capabilities and Configuration 2-2 */ + volatile uint8_t CH_FLASH_CAPCFG2_2; + /* 0x1B: Channel 3 Capabilities and Configuration 2-3 */ + volatile uint8_t CH_FLASH_CAPCFG2_3; + + /* 0x1c-0x1f: Reserved2 */ + volatile uint8_t reserved2[4]; + /* 0x20-0x8f: Reserved3 */ + volatile uint8_t reserved3[0x70]; + + /* 0x90: eSPI PC Control 0 */ + volatile uint8_t ESPCTRL0; + /* 0x91: eSPI PC Control 1 */ + volatile uint8_t ESPCTRL1; + /* 0x92: eSPI PC Control 2 */ + volatile uint8_t ESPCTRL2; + /* 0x93: eSPI PC Control 3 */ + volatile uint8_t ESPCTRL3; + /* 0x94: eSPI PC Control 4 */ + volatile uint8_t ESPCTRL4; + /* 0x95: eSPI PC Control 5 */ + volatile uint8_t ESPCTRL5; + /* 0x96: eSPI PC Control 6 */ + volatile uint8_t ESPCTRL6; + /* 0x97: eSPI PC Control 7 */ + volatile uint8_t ESPCTRL7; + /* 0x98-0x9f: Reserved4 */ + volatile uint8_t reserved4[8]; + + /* 0xa0: eSPI General Control 0 */ + volatile uint8_t ESGCTRL0; + /* 0xa1: eSPI General Control 1 */ + volatile uint8_t ESGCTRL1; + /* 0xa2: eSPI General Control 2 */ + volatile uint8_t ESGCTRL2; + /* 0xa3: eSPI General Control 3 */ + volatile uint8_t ESGCTRL3; + /* 0xa4-0xaf: Reserved5 */ + volatile uint8_t reserved5[12]; + + /* 0xb0: eSPI Upstream Control 0 */ + volatile uint8_t ESUCTRL0; + /* 0xb1: eSPI Upstream Control 1 */ + volatile uint8_t ESUCTRL1; + /* 0xb2: eSPI Upstream Control 2 */ + volatile uint8_t ESUCTRL2; + /* 0xb3: eSPI Upstream Control 3 */ + volatile uint8_t ESUCTRL3; + /* 0xb4-0xb5: Reserved6 */ + volatile uint8_t reserved6[2]; + /* 0xb6: eSPI Upstream Control 6 */ + volatile uint8_t ESUCTRL6; + /* 0xb7: eSPI Upstream Control 7 */ + volatile uint8_t ESUCTRL7; + /* 0xb8: eSPI Upstream Control 8 */ + volatile uint8_t ESUCTRL8; + /* 0xb9-0xbf: Reserved7 */ + volatile uint8_t reserved7[7]; + + /* 0xc0: eSPI OOB Control 0 */ + volatile uint8_t ESOCTRL0; + /* 0xc1: eSPI OOB Control 1 */ + volatile uint8_t ESOCTRL1; + /* 0xc2-0xc3: Reserved8 */ + volatile uint8_t reserved8[2]; + /* 0xc4: eSPI OOB Control 4 */ + volatile uint8_t ESOCTRL4; + /* 0xc5-0xcf: Reserved9 */ + volatile uint8_t reserved9[11]; + + /* 0xd0: eSPI SAFS Control 0 */ + volatile uint8_t ESPISAFSC0; + /* 0xd1: eSPI SAFS Control 1 */ + volatile uint8_t ESPISAFSC1; + /* 0xd2: eSPI SAFS Control 2 */ + volatile uint8_t ESPISAFSC2; + /* 0xd3: eSPI SAFS Control 3 */ + volatile uint8_t ESPISAFSC3; + /* 0xd4: eSPI SAFS Control 4 */ + volatile uint8_t ESPISAFSC4; + /* 0xd5: eSPI SAFS Control 5 */ + volatile uint8_t ESPISAFSC5; + /* 0xd6: eSPI SAFS Control 6 */ + volatile uint8_t ESPISAFSC6; + /* 0xd7: eSPI SAFS Control 7 */ + volatile uint8_t ESPISAFSC7; +}; + +/* + * eSPI VW registers + */ +struct espi_vw_regs { + /* 0x00-0x7f: VW index */ + volatile uint8_t VW_INDEX[0x80]; + /* 0x80-0x8f: Reserved1 */ + volatile uint8_t reserved1[0x10]; + /* 0x90: VW Contrl 0 */ + volatile uint8_t VWCTRL0; + /* 0x91: VW Contrl 1 */ + volatile uint8_t VWCTRL1; + /* 0x92: VW Contrl 2 */ + volatile uint8_t VWCTRL2; + /* 0x93: VW Contrl 3 */ + volatile uint8_t VWCTRL3; + /* 0x94: Reserved2 */ + volatile uint8_t reserved2; + /* 0x95: VW Contrl 5 */ + volatile uint8_t VWCTRL5; + /* 0x96: VW Contrl 6 */ + volatile uint8_t VWCTRL6; + /* 0x97: VW Contrl 7 */ + volatile uint8_t VWCTRL7; + /* 0x98-0x99: Reserved3 */ + volatile uint8_t reserved3[2]; +}; +#endif /* !__ASSEMBLER__ */ #endif /* CHIP_CHIPREGS_H */ diff --git a/soc/riscv/riscv-ite/common/soc_espi.h b/soc/riscv/riscv-ite/common/soc_espi.h new file mode 100644 index 00000000000..2273680273c --- /dev/null +++ b/soc/riscv/riscv-ite/common/soc_espi.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021 ITE Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ITE_IT8XXX2_SOC_ESPI_H_ +#define _ITE_IT8XXX2_SOC_ESPI_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESPI_IT8XXX2_SOC_DEV DEVICE_DT_GET(DT_NODELABEL(espi0)) + +/** + * @brief eSPI input pad gating + * + * @param dev pointer to eSPI device + * @param enable/disable eSPI pad + */ +void espi_it8xxx2_enable_pad_ctrl(const struct device *dev, bool enable); + +#ifdef __cplusplus +} +#endif + +#endif /* _ITE_IT8XXX2_SOC_ESPI_H_ */ diff --git a/soc/riscv/riscv-ite/it8xxx2/soc.c b/soc/riscv/riscv-ite/it8xxx2/soc.c index 8928c6565eb..c203560e444 100644 --- a/soc/riscv/riscv-ite/it8xxx2/soc.c +++ b/soc/riscv/riscv-ite/it8xxx2/soc.c @@ -10,6 +10,7 @@ #include #include #include +#include "soc_espi.h" #include #ifdef CONFIG_SOC_IT8XXX2_PLL_FLASH_48M @@ -105,18 +106,16 @@ static void chip_configure_pll(const struct pll_config_t *pll) ((IT8XXX2_ECPM_SCDCR3 & 0xf) != pll->div_ec)) { #ifdef CONFIG_ESPI /* - * TODO: implement me * We have to disable eSPI pad before changing * PLL sequence or sequence will fail if CS# pin is low. */ + espi_it8xxx2_enable_pad_ctrl(ESPI_IT8XXX2_SOC_DEV, false); #endif /* Run change PLL sequence */ chip_run_pll_sequence(pll); #ifdef CONFIG_ESPI - /* - * TODO: implement me - * Enable eSPI pad after changing PLL sequence - */ + /* Enable eSPI pad after changing PLL sequence */ + espi_it8xxx2_enable_pad_ctrl(ESPI_IT8XXX2_SOC_DEV, true); #endif } }