blob: f59f3728bfd2dd6c33ea9a3eae98c38d5e160435 [file] [log] [blame]
/* Copyright 2017 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* ESPI module for Chrome EC */
#include "console.h"
#include "espi.h"
#include "gpio.h"
#include "hooks.h"
#include "port80.h"
#include "power.h"
#include "registers.h"
#include "system.h"
#include "system_boot_time.h"
#include "task.h"
#include "uart.h"
#include "util.h"
/* Console output macros */
#define CPRINTS(format, args...) cprints(CC_LPC, format, ##args)
struct vw_channel_t {
uint8_t index; /* VW index of signal */
uint8_t level_mask; /* level bit of signal */
uint8_t valid_mask; /* valid bit of signal */
};
/* VW settings after the controller 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_40_SUS_ACK) },
#endif
};
/* VW settings after the controller 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 controller 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) },
};
/* VW settings at host startup */
static const struct vw_channel_t vw_host_startup_setting[] = {
{ ESPI_SYSTEM_EVENT_VW_IDX_6,
VW_LEVEL_FIELD(VW_IDX_6_SCI | VW_IDX_6_SMI | VW_IDX_6_RCIN |
VW_IDX_6_HOST_RST_ACK),
VW_VALID_FIELD(VW_IDX_6_SCI | VW_IDX_6_SMI | VW_IDX_6_RCIN |
VW_IDX_6_HOST_RST_ACK) },
};
#define VW_CHAN(name, idx, level, valid) \
[(name - VW_SIGNAL_START)] = { idx, level, valid }
/* VW signals used in eSPI (NOTE: must match order of enum espi_vw_signal). */
static const struct vw_channel_t vw_channel_list[] = {
/* index 02h: controller to peripheral. */
VW_CHAN(VW_SLP_S3_L, ESPI_SYSTEM_EVENT_VW_IDX_2,
VW_LEVEL_FIELD(VW_IDX_2_SLP_S3),
VW_VALID_FIELD(VW_IDX_2_SLP_S3)),
VW_CHAN(VW_SLP_S4_L, ESPI_SYSTEM_EVENT_VW_IDX_2,
VW_LEVEL_FIELD(VW_IDX_2_SLP_S4),
VW_VALID_FIELD(VW_IDX_2_SLP_S4)),
VW_CHAN(VW_SLP_S5_L, ESPI_SYSTEM_EVENT_VW_IDX_2,
VW_LEVEL_FIELD(VW_IDX_2_SLP_S5),
VW_VALID_FIELD(VW_IDX_2_SLP_S5)),
/* index 03h: controller to peripheral. */
VW_CHAN(VW_SUS_STAT_L, ESPI_SYSTEM_EVENT_VW_IDX_3,
VW_LEVEL_FIELD(VW_IDX_3_SUS_STAT),
VW_VALID_FIELD(VW_IDX_3_SUS_STAT)),
VW_CHAN(VW_PLTRST_L, ESPI_SYSTEM_EVENT_VW_IDX_3,
VW_LEVEL_FIELD(VW_IDX_3_PLTRST),
VW_VALID_FIELD(VW_IDX_3_PLTRST)),
VW_CHAN(VW_OOB_RST_WARN, ESPI_SYSTEM_EVENT_VW_IDX_3,
VW_LEVEL_FIELD(VW_IDX_3_OOB_RST_WARN),
VW_VALID_FIELD(VW_IDX_3_OOB_RST_WARN)),
/* index 04h: peripheral to controller. */
VW_CHAN(VW_OOB_RST_ACK, ESPI_SYSTEM_EVENT_VW_IDX_4,
VW_LEVEL_FIELD(VW_IDX_4_OOB_RST_ACK),
VW_VALID_FIELD(VW_IDX_4_OOB_RST_ACK)),
VW_CHAN(VW_WAKE_L, ESPI_SYSTEM_EVENT_VW_IDX_4,
VW_LEVEL_FIELD(VW_IDX_4_WAKE), VW_VALID_FIELD(VW_IDX_4_WAKE)),
VW_CHAN(VW_PME_L, ESPI_SYSTEM_EVENT_VW_IDX_4,
VW_LEVEL_FIELD(VW_IDX_4_PME), VW_VALID_FIELD(VW_IDX_4_PME)),
/* index 05h: peripheral to controller. */
VW_CHAN(VW_ERROR_FATAL, ESPI_SYSTEM_EVENT_VW_IDX_5,
VW_LEVEL_FIELD(VW_IDX_5_FATAL), VW_VALID_FIELD(VW_IDX_5_FATAL)),
VW_CHAN(VW_ERROR_NON_FATAL, ESPI_SYSTEM_EVENT_VW_IDX_5,
VW_LEVEL_FIELD(VW_IDX_5_NON_FATAL),
VW_VALID_FIELD(VW_IDX_5_NON_FATAL)),
VW_CHAN(VW_PERIPHERAL_BTLD_STATUS_DONE, ESPI_SYSTEM_EVENT_VW_IDX_5,
VW_LEVEL_FIELD(VW_IDX_5_BTLD_STATUS_DONE),
VW_VALID_FIELD(VW_IDX_5_BTLD_STATUS_DONE)),
/* index 06h: peripheral to controller. */
VW_CHAN(VW_SCI_L, ESPI_SYSTEM_EVENT_VW_IDX_6,
VW_LEVEL_FIELD(VW_IDX_6_SCI), VW_VALID_FIELD(VW_IDX_6_SCI)),
VW_CHAN(VW_SMI_L, ESPI_SYSTEM_EVENT_VW_IDX_6,
VW_LEVEL_FIELD(VW_IDX_6_SMI), VW_VALID_FIELD(VW_IDX_6_SMI)),
VW_CHAN(VW_RCIN_L, ESPI_SYSTEM_EVENT_VW_IDX_6,
VW_LEVEL_FIELD(VW_IDX_6_RCIN), VW_VALID_FIELD(VW_IDX_6_RCIN)),
VW_CHAN(VW_HOST_RST_ACK, ESPI_SYSTEM_EVENT_VW_IDX_6,
VW_LEVEL_FIELD(VW_IDX_6_HOST_RST_ACK),
VW_VALID_FIELD(VW_IDX_6_HOST_RST_ACK)),
/* index 07h: controller to peripheral. */
VW_CHAN(VW_HOST_RST_WARN, ESPI_SYSTEM_EVENT_VW_IDX_7,
VW_LEVEL_FIELD(VW_IDX_7_HOST_RST_WARN),
VW_VALID_FIELD(VW_IDX_7_HOST_RST_WARN)),
/* index 40h: peripheral to controller. */
VW_CHAN(VW_SUS_ACK, ESPI_SYSTEM_EVENT_VW_IDX_40,
VW_LEVEL_FIELD(VW_IDX_40_SUS_ACK),
VW_VALID_FIELD(VW_IDX_40_SUS_ACK)),
/* index 41h: controller to peripheral. */
VW_CHAN(VW_SUS_WARN_L, ESPI_SYSTEM_EVENT_VW_IDX_41,
VW_LEVEL_FIELD(VW_IDX_41_SUS_WARN),
VW_VALID_FIELD(VW_IDX_41_SUS_WARN)),
VW_CHAN(VW_SUS_PWRDN_ACK_L, ESPI_SYSTEM_EVENT_VW_IDX_41,
VW_LEVEL_FIELD(VW_IDX_41_SUS_PWRDN_ACK),
VW_VALID_FIELD(VW_IDX_41_SUS_PWRDN_ACK)),
VW_CHAN(VW_SLP_A_L, ESPI_SYSTEM_EVENT_VW_IDX_41,
VW_LEVEL_FIELD(VW_IDX_41_SLP_A),
VW_VALID_FIELD(VW_IDX_41_SLP_A)),
/* index 42h: controller to peripheral. */
VW_CHAN(VW_SLP_LAN, ESPI_SYSTEM_EVENT_VW_IDX_42,
VW_LEVEL_FIELD(VW_IDX_42_SLP_LAN),
VW_VALID_FIELD(VW_IDX_42_SLP_LAN)),
VW_CHAN(VW_SLP_WLAN, ESPI_SYSTEM_EVENT_VW_IDX_42,
VW_LEVEL_FIELD(VW_IDX_42_SLP_WLAN),
VW_VALID_FIELD(VW_IDX_42_SLP_WLAN)),
};
BUILD_ASSERT(ARRAY_SIZE(vw_channel_list) == VW_SIGNAL_COUNT);
/* Get vw index & value information by signal */
static int espi_vw_get_signal_index(enum espi_vw_signal event)
{
uint32_t i = event - VW_SIGNAL_START;
return (i < ARRAY_SIZE(vw_channel_list)) ? i : -1;
}
/**
* Set eSPI Virtual-Wire signal to Host
*
* @param signal vw signal needs to set
* @param level level of vw signal
* @return EC_SUCCESS, or non-zero if error.
*/
int espi_vw_set_wire(enum espi_vw_signal signal, uint8_t level)
{
/* Get index of vw signal list by signale name */
int i = espi_vw_get_signal_index(signal);
if (i < 0)
return EC_ERROR_PARAM1;
/* critical section with interrupts off */
interrupt_disable();
if (level)
IT83XX_ESPI_VWIDX(vw_channel_list[i].index) |=
vw_channel_list[i].level_mask;
else
IT83XX_ESPI_VWIDX(vw_channel_list[i].index) &=
~vw_channel_list[i].level_mask;
/* restore interrupts */
interrupt_enable();
return EC_SUCCESS;
}
/**
* Get eSPI Virtual-Wire signal from host
*
* @param signal vw signal needs to get
* @return 1: set by host, otherwise: no signal
*/
int espi_vw_get_wire(enum espi_vw_signal signal)
{
/* Get index of vw signal list by signale name */
int i = espi_vw_get_signal_index(signal);
if (i < 0)
return 0;
/* Not valid */
if (!(IT83XX_ESPI_VWIDX(vw_channel_list[i].index) &
vw_channel_list[i].valid_mask))
return 0;
return !!(IT83XX_ESPI_VWIDX(vw_channel_list[i].index) &
vw_channel_list[i].level_mask);
}
/**
* Enable VW interrupt of power sequence signal
*
* @param signal vw signal needs to enable interrupt
* @return EC_SUCCESS, or non-zero if error.
*/
int espi_vw_enable_wire_int(enum espi_vw_signal signal)
{
/*
* Common code calls this function to enable VW interrupt of power
* sequence signal.
* IT83xx only use a bit (bit7@IT83XX_ESPI_VWCTRL0) to enable VW
* interrupt.
* VW interrupt will be triggerd with any updated VW index flag
* if this control bit is set.
* So we will always return success here.
*/
return EC_SUCCESS;
}
/**
* Disable VW interrupt of power sequence signal
*
* @param signal vw signal needs to disable interrupt
* @return EC_SUCCESS, or non-zero if error.
*/
int espi_vw_disable_wire_int(enum espi_vw_signal signal)
{
/*
* We can't disable VW interrupt of power sequence signal
* individually.
*/
return EC_ERROR_UNIMPLEMENTED;
}
/* Configure virtual wire outputs */
static void espi_configure_vw(const struct vw_channel_t *settings,
size_t entries)
{
size_t i;
for (i = 0; i < entries; i++)
IT83XX_ESPI_VWIDX(settings[i].index) |=
(settings[i].level_mask | settings[i].valid_mask);
}
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, 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, 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));
}
#ifdef CONFIG_CHIPSET_RESET_HOOK
static void espi_chipset_reset(void)
{
hook_notify(HOOK_CHIPSET_RESET);
update_ap_boot_time(ESPIRST);
}
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) {
espi_vw_host_startup();
update_ap_boot_time(PLTRST_HIGH);
} 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);
update_ap_boot_time(PLTRST_LOW);
}
CPRINTS("VW PLTRST_L %sasserted", pltrst ? "de" : "");
}
if (flag_changed & VW_LEVEL_FIELD(VW_IDX_3_OOB_RST_WARN))
espi_vw_set_wire(VW_OOB_RST_ACK,
espi_vw_get_wire(VW_OOB_RST_WARN));
}
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);
if (flag_changed & VW_LEVEL_FIELD(VW_IDX_2_SLP_S4))
power_signal_interrupt(VW_SLP_S4_L);
if (flag_changed & VW_LEVEL_FIELD(VW_IDX_2_SLP_S5))
power_signal_interrupt(VW_SLP_S5_L);
}
struct vw_interrupt_t {
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[] = {
[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[] = {
[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
/*
* 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[ARRAY_SIZE(vw_isr_list)];
void espi_vw_interrupt(void)
{
int i;
uint8_t vwidx_updated = IT83XX_ESPI_VWCTRL1;
#ifdef IT83XX_ESPI_VWCTRL1_WRITE_FF_CLEAR
/* For IT8320BX, we have to write 0xff to clear pending bit.*/
IT83XX_ESPI_VWCTRL1 = 0xff;
#else
/* write-1 to clear */
IT83XX_ESPI_VWCTRL1 = vwidx_updated;
#endif
task_clear_pending_irq(IT83XX_IRQ_ESPI_VW);
for (i = 0; i < ARRAY_SIZE(vw_isr_list); i++) {
if (vwidx_updated & BIT(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, i);
vw_index_flag[i] = idx_flag;
}
}
}
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);
}
#ifdef IT83XX_ESPI_RESET_MODULE_BY_FW
void __ram_code espi_fw_reset_module(void)
{
/*
* (b/111480168): Force a reset of logic VCC domain in EC. This will
* reset both LPC and eSPI blocks. The IT8320DX spec describes the
* purpose of these bits as deciding whether VCC power status is used as
* an internal "power good" signal. However, toggling this field while
* VCC is applied results in resettig VCC domain logic in EC. This code
* must reside in SRAM to prevent DMA address corruption.
*
* bit[7-6]:
* 00b: The VCC power status is treated as power-off.
* 01b: The VCC power status is treated as power-on.
*/
IT83XX_GCTRL_RSTS = (IT83XX_GCTRL_RSTS & ~0xc0);
IT83XX_GCTRL_RSTS = (IT83XX_GCTRL_RSTS & ~0xc0) | BIT(6);
}
#endif
void espi_reset_pin_asserted_interrupt(enum gpio_signal signal)
{
#ifdef IT83XX_ESPI_RESET_MODULE_BY_FW
espi_fw_reset_module();
/*
* bit[7], enable P80L function.
* bit[6], accept port 80h cycle.
* bit[1-0], 10b: I2EC is read-only.
*/
IT83XX_GCTRL_SPCTRL1 |= 0xC2;
#endif
/* reset vw_index_flag when espi_reset# asserted. */
espi_reset_vw_index_flags();
}
static int espi_get_reset_enable_config(void)
{
uint8_t config;
const struct gpio_info *espi_rst = gpio_list + GPIO_ESPI_RESET_L;
/*
* Determine if eSPI HW reset is connected to eiter B7 or D2.
* bit[2-1]:
* 00b: reserved.
* 01b: espi_reset# is enabled on GPB7.
* 10b: espi_reset# is enabled on GPD2.
* 11b: reset is disabled.
*/
if (espi_rst->port == GPIO_D && espi_rst->mask == BIT(2)) {
config = IT83XX_GPIO_GCR_LPC_RST_D2;
} else if (espi_rst->port == GPIO_B && espi_rst->mask == BIT(7)) {
config = IT83XX_GPIO_GCR_LPC_RST_B7;
} else {
config = IT83XX_GPIO_GCR_LPC_RST_DISABLE;
CPRINTS("EC's espi_reset pin is not enabled correctly");
}
return config;
}
static void espi_enable_reset(void)
{
int config = espi_get_reset_enable_config();
#ifdef IT83XX_ESPI_RESET_MODULE_BY_FW
/*
* Need to overwrite the config to ensure that eSPI HW reset is
* disabled. The reset function is instead handled by FW in the
* interrupt handler.
*/
config = IT83XX_GPIO_GCR_LPC_RST_DISABLE;
CPRINTS("EC's espi_reset pin hw auto reset is disabled");
#endif
IT83XX_GPIO_GCR = (IT83XX_GPIO_GCR & ~0x6) |
(config << IT83XX_GPIO_GCR_LPC_RST_POS);
/* enable interrupt of EC's espi_reset pin */
gpio_clear_pending_interrupt(GPIO_ESPI_RESET_L);
gpio_enable_interrupt(GPIO_ESPI_RESET_L);
}
/* Interrupt event of controller enables the VW channel. */
static void espi_vw_en_asserted(uint8_t evt)
{
/*
* Configure peripheral to controller virtual wire outputs after
* receiving the event of controller enables the VW channel.
*/
espi_configure_vw(en_vw_setting, ARRAY_SIZE(en_vw_setting));
}
/* Interrupt event of controller enables the OOB channel. */
static void espi_oob_en_asserted(uint8_t evt)
{
/*
* Configure peripheral to controller virtual wire outputs after
* receiving the event of controller enables the OOB channel.
*/
espi_configure_vw(en_oob_setting, ARRAY_SIZE(en_oob_setting));
}
/* Interrupt event of controller enables the flash channel. */
static void espi_flash_en_asserted(uint8_t evt)
{
/*
* Configure peripheral to controller virtual wire outputs after
* receiving the event of controller 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 & BIT(i))
espi_isr[i](i);
}
/*
* bit7: the peripheral has received a peripheral posted/completion.
* This bit indicates the peripheral 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!");
}
task_clear_pending_irq(IT83XX_IRQ_ESPI);
}
#ifdef IT83XX_ESPI_INHIBIT_CS_BY_PAD_DISABLED
/* Enable/Disable eSPI pad */
void espi_enable_pad(int enable)
{
if (enable)
/* Enable eSPI pad. */
IT83XX_ESPI_ESGCTRL2 &= ~BIT(6);
else
/* Disable eSPI pad. */
IT83XX_ESPI_ESGCTRL2 |= BIT(6);
}
#endif
void espi_init(void)
{
/*
* bit[2-0], the maximum frequency of operation supported by peripheral:
* 000b: 20MHz
* 001b: 25MHz
* 010b: 33MHz
* 011b: 50MHz
* 100b: 66MHz
*/
#ifdef IT83XX_ESPI_PERIPHERAL_MAX_FREQ_CONFIGURABLE
IT83XX_ESPI_GCAC1 = (IT83XX_ESPI_GCAC1 & ~0x7) | BIT(2);
#endif
/* reset vw_index_flag at initialization */
espi_reset_vw_index_flags();
/*
* bit[3]: The reset source of PNPCFG is RSTPNP bit in RSTCH
* register and WRST#.
*/
IT83XX_GCTRL_RSTS &= ~BIT(3);
task_clear_pending_irq(IT83XX_IRQ_ESPI_VW);
/* bit7: VW interrupt enable */
IT83XX_ESPI_VWCTRL0 |= BIT(7);
task_enable_irq(IT83XX_IRQ_ESPI_VW);
/* bit7: eSPI interrupt enable */
IT83XX_ESPI_ESGCTRL1 |= BIT(7);
/* bit4: eSPI to WUC enable */
IT83XX_ESPI_ESGCTRL2 |= BIT(4);
task_enable_irq(IT83XX_IRQ_ESPI);
/* enable interrupt and reset from eSPI_reset# */
espi_enable_reset();
}