diff options
author | Dino Li <Dino.Li@ite.com.tw> | 2018-06-05 13:41:58 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-06-06 01:16:11 -0700 |
commit | c06b3916770535270faf790c43866708b433bfd4 (patch) | |
tree | 09b248dea231759ed7396b4ad26ec09f954688be | |
parent | ef25dff82aad8d75cada88eff8fa09d2139dac20 (diff) | |
download | chrome-ec-c06b3916770535270faf790c43866708b433bfd4.tar.gz |
it83xx: espi: enable eSPI interrupt
This patch reconfigure virtual wire outputs for
each eSPI boot flow.
BUG=b:80250980
BRANCH=none
TEST=boot to kernel on bip.
Change-Id: Ia36cf3e582982f8d7c2fd7179e56909f0f80efd8
Signed-off-by: Dino Li <Dino.Li@ite.com.tw>
Reviewed-on: https://chromium-review.googlesource.com/1078827
Reviewed-by: Furquan Shaikh <furquan@chromium.org>
Reviewed-by: Jett Rink <jettrink@chromium.org>
-rw-r--r-- | chip/it83xx/espi.c | 225 | ||||
-rw-r--r-- | chip/it83xx/registers.h | 7 |
2 files changed, 172 insertions, 60 deletions
diff --git a/chip/it83xx/espi.c b/chip/it83xx/espi.c index e46a74ad4f..6bd74fec1e 100644 --- a/chip/it83xx/espi.c +++ b/chip/it83xx/espi.c @@ -16,8 +16,6 @@ #include "uart.h" #include "util.h" -#define CHIP_ESPI_VW_INTERRUPT_NUM 8 - /* Console output macros */ #define CPRINTS(format, args...) cprints(CC_LPC, format, ## args) @@ -27,29 +25,29 @@ struct vw_channel_t { uint8_t valid_mask; /* valid bit of signal */ }; -/* VW settings at initialization */ -#ifdef CONFIG_CHIPSET_GEMINILAKE -static const struct vw_channel_t vw_init_setting[] = { - {ESPI_SYSTEM_EVENT_VW_IDX_4, +/* VW settings after the master enables the VW channel. */ +static const struct vw_channel_t en_vw_setting[] = { + /* EC sends SUS_ACK# = 1 VW to PCH. That does not apply to GLK SoC. */ +#ifndef CONFIG_CHIPSET_GEMINILAKE + {ESPI_SYSTEM_EVENT_VW_IDX_40, VW_LEVEL_FIELD(0), - VW_VALID_FIELD(VW_IDX_4_OOB_RST_ACK)}, - {ESPI_SYSTEM_EVENT_VW_IDX_5, - VW_LEVEL_FIELD(VW_IDX_5_BTLD_STATUS_DONE), - VW_VALID_FIELD(VW_IDX_5_BTLD_STATUS_DONE)}, + VW_VALID_FIELD(VW_IDX_40_SUS_ACK)}, +#endif }; -#else -static const struct vw_channel_t vw_init_setting[] = { + +/* VW settings after the master enables the OOB channel. */ +static const struct vw_channel_t en_oob_setting[] = { {ESPI_SYSTEM_EVENT_VW_IDX_4, VW_LEVEL_FIELD(0), VW_VALID_FIELD(VW_IDX_4_OOB_RST_ACK)}, +}; + +/* VW settings after the master enables the flash channel. */ +static const struct vw_channel_t en_flash_setting[] = { {ESPI_SYSTEM_EVENT_VW_IDX_5, VW_LEVEL_FIELD(VW_IDX_5_BTLD_STATUS_DONE), VW_VALID_FIELD(VW_IDX_5_BTLD_STATUS_DONE)}, - {ESPI_SYSTEM_EVENT_VW_IDX_40, - VW_LEVEL_FIELD(0), - VW_VALID_FIELD(VW_IDX_40_SUS_ACK)}, }; -#endif /* VW settings at host startup */ static const struct vw_channel_t vw_host_startup_setting[] = { @@ -265,47 +263,68 @@ int espi_vw_disable_wire_int(enum espi_vw_signal signal) return EC_ERROR_UNIMPLEMENTED; } -static void espi_vw_host_startup(void) +/* Configure virtual wire outputs */ +static void espi_configure_vw(const struct vw_channel_t *settings, + size_t entries) { - int i; + size_t i; - for (i = 0; i < ARRAY_SIZE(vw_host_startup_setting); i++) - IT83XX_ESPI_VWIDX(vw_host_startup_setting[i].index) = - (vw_host_startup_setting[i].level_mask | - vw_host_startup_setting[i].valid_mask); + for (i = 0; i < entries; i++) + IT83XX_ESPI_VWIDX(settings[i].index) |= + (settings[i].level_mask | settings[i].valid_mask); } -static void espi_vw_no_isr(uint8_t flag_changed) +static void espi_vw_host_startup(void) { + espi_configure_vw(vw_host_startup_setting, + ARRAY_SIZE(vw_host_startup_setting)); +} + +static void espi_vw_no_isr(uint8_t flag_changed, uint8_t vw_evt) +{ + CPRINTS("espi VW interrupt event is ignored! (bit%d at VWCTRL1)", + vw_evt); } #ifndef CONFIG_CHIPSET_GEMINILAKE -static void espi_vw_idx41_isr(uint8_t flag_changed) +static void espi_vw_idx41_isr(uint8_t flag_changed, uint8_t vw_evt) { if (flag_changed & VW_LEVEL_FIELD(VW_IDX_41_SUS_WARN)) espi_vw_set_wire(VW_SUS_ACK, espi_vw_get_wire(VW_SUS_WARN_L)); } #endif -static void espi_vw_idx7_isr(uint8_t flag_changed) +static void espi_vw_idx7_isr(uint8_t flag_changed, uint8_t vw_evt) { if (flag_changed & VW_LEVEL_FIELD(VW_IDX_7_HOST_RST_WARN)) espi_vw_set_wire(VW_HOST_RST_ACK, espi_vw_get_wire(VW_HOST_RST_WARN)); } -static void espi_vw_idx3_isr(uint8_t flag_changed) +#ifdef CONFIG_CHIPSET_RESET_HOOK +static void espi_chipset_reset(void) +{ + hook_notify(HOOK_CHIPSET_RESET); +} +DECLARE_DEFERRED(espi_chipset_reset); +#endif + +static void espi_vw_idx3_isr(uint8_t flag_changed, uint8_t vw_evt) { if (flag_changed & VW_LEVEL_FIELD(VW_IDX_3_PLTRST)) { int pltrst = espi_vw_get_wire(VW_PLTRST_L); - if (pltrst) + if (pltrst) { espi_vw_host_startup(); - else + } else { +#ifdef CONFIG_CHIPSET_RESET_HOOK + hook_call_deferred(&espi_chipset_reset_data, MSEC); +#endif /* Store port 80 reset event */ port_80_write(PORT_80_EVENT_RESET); + } - CPRINTS("PLTRST_L %sasserted", pltrst ? "de" : ""); + CPRINTS("VW PLTRST_L %sasserted", pltrst ? "de" : ""); } if (flag_changed & VW_LEVEL_FIELD(VW_IDX_3_OOB_RST_WARN)) @@ -313,7 +332,7 @@ static void espi_vw_idx3_isr(uint8_t flag_changed) espi_vw_get_wire(VW_OOB_RST_WARN)); } -static void espi_vw_idx2_isr(uint8_t flag_changed) +static void espi_vw_idx2_isr(uint8_t flag_changed, uint8_t vw_evt) { if (flag_changed & VW_LEVEL_FIELD(VW_IDX_2_SLP_S3)) power_signal_interrupt(VW_SLP_S3_L); @@ -324,31 +343,35 @@ static void espi_vw_idx2_isr(uint8_t flag_changed) } struct vw_interrupt_t { - void (*vw_isr)(uint8_t flag_changed); + void (*vw_isr)(uint8_t flag_changed, uint8_t vw_evt); uint8_t vw_index; }; +/* + * The ISR of espi VW interrupt in array needs to match bit order in + * IT83XX_ESPI_VWCTRL1 register. + */ #ifdef CONFIG_CHIPSET_GEMINILAKE -static const struct vw_interrupt_t vw_isr_list[CHIP_ESPI_VW_INTERRUPT_NUM] = { - {espi_vw_idx2_isr, ESPI_SYSTEM_EVENT_VW_IDX_2}, - {espi_vw_idx3_isr, ESPI_SYSTEM_EVENT_VW_IDX_3}, - {espi_vw_idx7_isr, ESPI_SYSTEM_EVENT_VW_IDX_7}, - {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_41}, - {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_42}, - {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_43}, - {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_44}, - {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_47}, +static const struct vw_interrupt_t vw_isr_list[] = { + [0] = {espi_vw_idx2_isr, ESPI_SYSTEM_EVENT_VW_IDX_2}, + [1] = {espi_vw_idx3_isr, ESPI_SYSTEM_EVENT_VW_IDX_3}, + [2] = {espi_vw_idx7_isr, ESPI_SYSTEM_EVENT_VW_IDX_7}, + [3] = {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_41}, + [4] = {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_42}, + [5] = {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_43}, + [6] = {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_44}, + [7] = {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_47}, }; #else -static const struct vw_interrupt_t vw_isr_list[CHIP_ESPI_VW_INTERRUPT_NUM] = { - {espi_vw_idx2_isr, ESPI_SYSTEM_EVENT_VW_IDX_2}, - {espi_vw_idx3_isr, ESPI_SYSTEM_EVENT_VW_IDX_3}, - {espi_vw_idx7_isr, ESPI_SYSTEM_EVENT_VW_IDX_7}, - {espi_vw_idx41_isr, ESPI_SYSTEM_EVENT_VW_IDX_41}, - {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_42}, - {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_43}, - {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_44}, - {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_47}, +static const struct vw_interrupt_t vw_isr_list[] = { + [0] = {espi_vw_idx2_isr, ESPI_SYSTEM_EVENT_VW_IDX_2}, + [1] = {espi_vw_idx3_isr, ESPI_SYSTEM_EVENT_VW_IDX_3}, + [2] = {espi_vw_idx7_isr, ESPI_SYSTEM_EVENT_VW_IDX_7}, + [3] = {espi_vw_idx41_isr, ESPI_SYSTEM_EVENT_VW_IDX_41}, + [4] = {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_42}, + [5] = {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_43}, + [6] = {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_44}, + [7] = {espi_vw_no_isr, ESPI_SYSTEM_EVENT_VW_IDX_47}, }; #endif @@ -356,7 +379,7 @@ static const struct vw_interrupt_t vw_isr_list[CHIP_ESPI_VW_INTERRUPT_NUM] = { * 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 vw_index_flag[CHIP_ESPI_VW_INTERRUPT_NUM]; +static uint8_t vw_index_flag[ARRAY_SIZE(vw_isr_list)]; void espi_vw_interrupt(void) { @@ -374,32 +397,108 @@ void espi_vw_interrupt(void) #endif task_clear_pending_irq(IT83XX_IRQ_ESPI_VW); - for (i = 0; i < CHIP_ESPI_VW_INTERRUPT_NUM; i++) { + for (i = 0; i < ARRAY_SIZE(vw_isr_list); i++) { if (vwidx_updated & (1 << i)) { uint8_t idx_flag; idx_flag = IT83XX_ESPI_VWIDX(vw_isr_list[i].vw_index); - vw_isr_list[i].vw_isr(vw_index_flag[i] ^ idx_flag); + vw_isr_list[i].vw_isr(vw_index_flag[i] ^ idx_flag, i); vw_index_flag[i] = idx_flag; } } } -void espi_interrupt(void) +static void espi_reset_vw_index_flags(void) +{ + int i; + + /* reset vw_index_flag */ + for (i = 0; i < ARRAY_SIZE(vw_isr_list); i++) + vw_index_flag[i] = IT83XX_ESPI_VWIDX(vw_isr_list[i].vw_index); +} + +/* Interrupt event of master enables the VW channel. */ +static void espi_vw_en_asserted(uint8_t evt) { + /* + * Configure slave to master virtual wire outputs after receiving + * the event of master enables the VW channel. + */ + espi_configure_vw(en_vw_setting, ARRAY_SIZE(en_vw_setting)); } -void espi_init(void) +/* Interrupt event of master enables the OOB channel. */ +static void espi_oob_en_asserted(uint8_t evt) +{ + /* + * Configure slave to master virtual wire outputs after receiving + * the event of master enables the OOB channel. + */ + espi_configure_vw(en_oob_setting, ARRAY_SIZE(en_oob_setting)); +} + +/* Interrupt event of master enables the flash channel. */ +static void espi_flash_en_asserted(uint8_t evt) +{ + /* + * Configure slave to master virtual wire outputs after receiving + * the event of master enables the flash channel. + */ + espi_configure_vw(en_flash_setting, ARRAY_SIZE(en_flash_setting)); +} + +static void espi_no_isr(uint8_t evt) +{ + CPRINTS("espi interrupt event is ignored! (bit%d at ESGCTRL0)", evt); +} + +/* + * The ISR of espi interrupt event in array need to be matched bit order in + * IT83XX_ESPI_ESGCTRL0 register. + */ +static void (*espi_isr[])(uint8_t evt) = { + [0] = espi_no_isr, + [1] = espi_vw_en_asserted, + [2] = espi_oob_en_asserted, + [3] = espi_flash_en_asserted, + [4] = espi_no_isr, + [5] = espi_no_isr, + [6] = espi_no_isr, + [7] = espi_no_isr, +}; + +void espi_interrupt(void) { int i; + /* get espi interrupt events */ + uint8_t espi_event = IT83XX_ESPI_ESGCTRL0; + + /* write-1 to clear */ + IT83XX_ESPI_ESGCTRL0 = espi_event; + /* process espi interrupt events */ + for (i = 0; i < ARRAY_SIZE(espi_isr); i++) { + if (espi_event & (1 << i)) + espi_isr[i](i); + } + /* + * bit7: the slave has received a peripheral posted/completion. + * This bit indicates the slave has received a packet from eSPI + * peripheral channel. We can check cycle type (bit[3-0] at ESPCTRL0) + * and make corresponding modification if needed. + */ + if (IT83XX_ESPI_ESPCTRL0 & ESPI_INTERRUPT_EVENT_PUT_PC) { + /* write-1-clear to release PC_FREE */ + IT83XX_ESPI_ESPCTRL0 = ESPI_INTERRUPT_EVENT_PUT_PC; + CPRINTS("A packet from peripheral channel is ignored!"); + } - for (i = 0; i < ARRAY_SIZE(vw_init_setting); i++) - IT83XX_ESPI_VWIDX(vw_init_setting[i].index) = - (vw_init_setting[i].level_mask | - vw_init_setting[i].valid_mask); + task_clear_pending_irq(IT83XX_IRQ_ESPI); +} - for (i = 0; i < CHIP_ESPI_VW_INTERRUPT_NUM; i++) - vw_index_flag[i] = IT83XX_ESPI_VWIDX(vw_isr_list[i].vw_index); +void espi_init(void) +{ + /* reset vw_index_flag at initialization */ + espi_reset_vw_index_flags(); /* * bit[3]: The reset source of PNPCFG is RSTPNP bit in RSTCH @@ -410,4 +509,10 @@ void espi_init(void) /* bit7: VW interrupt enable */ IT83XX_ESPI_VWCTRL0 |= (1 << 7); task_enable_irq(IT83XX_IRQ_ESPI_VW); + + /* bit7: eSPI interrupt enable */ + IT83XX_ESPI_ESGCTRL1 |= (1 << 7); + /* bit4: eSPI to WUC enable */ + IT83XX_ESPI_ESGCTRL2 |= (1 << 4); + task_enable_irq(IT83XX_IRQ_ESPI); } diff --git a/chip/it83xx/registers.h b/chip/it83xx/registers.h index a2f55d6e4e..4b6a702d15 100644 --- a/chip/it83xx/registers.h +++ b/chip/it83xx/registers.h @@ -1226,6 +1226,11 @@ enum usbpd_port { #define IT83XX_ESPI_BASE 0x00F03100 +#define IT83XX_ESPI_ESPCTRL0 REG8(IT83XX_ESPI_BASE+0x90) +#define IT83XX_ESPI_ESGCTRL0 REG8(IT83XX_ESPI_BASE+0xA0) +#define IT83XX_ESPI_ESGCTRL1 REG8(IT83XX_ESPI_BASE+0xA1) +#define IT83XX_ESPI_ESGCTRL2 REG8(IT83XX_ESPI_BASE+0xA2) + /* eSPI VW */ #define IT83XX_ESPI_VW_BASE 0x00F03200 #define IT83XX_ESPI_VWIDX(i) REG8(IT83XX_ESPI_VW_BASE+(i)) @@ -1282,6 +1287,8 @@ enum usbpd_port { #define ESPI_SYSTEM_EVENT_VW_IDX_47 0x47 #define IT83XX_ESPI_VWCTRL0 REG8(IT83XX_ESPI_VW_BASE+0x90) +#define ESPI_INTERRUPT_EVENT_PUT_PC (1 << 7) + #define IT83XX_ESPI_VWCTRL1 REG8(IT83XX_ESPI_VW_BASE+0x91) #define IT83XX_ESPI_VWCTRL2 REG8(IT83XX_ESPI_VW_BASE+0x92) #define IT83XX_ESPI_VWCTRL3 REG8(IT83XX_ESPI_VW_BASE+0x93) |