driver: espi: add espi vw channel driver for rts5912

add espi vw channel driver for rts5912

Signed-off-by: jhan bo chao <jhan_bo_chao@realtek.com>
This commit is contained in:
jhan bo chao 2025-05-04 01:53:55 +08:00 committed by Benjamin Cabé
commit 1c461e38ca

View file

@ -45,6 +45,891 @@ struct espi_rts5912_data {
#endif
};
/*
* =========================================================================
* ESPI VWIRE channel
* =========================================================================
*/
#ifdef CONFIG_ESPI_VWIRE_CHANNEL
#define VW_CH_IDX2 0x02UL
#define VW_CH_IDX3 0x03UL
#define VW_CH_IDX4 0x04UL
#define VW_CH_IDX5 0x05UL
#define VW_CH_IDX6 0x06UL
#define VW_CH_IDX7 0x07UL
#define VW_CH_IDX40 0x40UL
#define VW_CH_IDX41 0x41UL
#define VW_CH_IDX42 0x42UL
#define VW_CH_IDX43 0x43UL
#define VW_CH_IDX44 0x44UL
#define VW_CH_IDX47 0x47UL
#define VW_CH_IDX4A 0x4AUL
#define VW_CH_IDX51 0x51UL
#define VW_CH_IDX61 0x61UL
struct espi_vw_channel {
uint8_t vw_index;
uint8_t level_mask;
uint8_t valid_mask;
};
struct espi_vw_signal_t {
enum espi_vwire_signal signal;
void (*vw_signal_callback)(const struct device *dev);
};
#define VW_CH(signal, index, level, valid) \
[signal] = {.vw_index = index, .level_mask = level, .valid_mask = valid}
static const struct espi_vw_channel vw_channel_list[] = {
VW_CH(ESPI_VWIRE_SIGNAL_SLP_S3, VW_CH_IDX2, BIT(0), BIT(4)),
VW_CH(ESPI_VWIRE_SIGNAL_SLP_S4, VW_CH_IDX2, BIT(1), BIT(5)),
VW_CH(ESPI_VWIRE_SIGNAL_SLP_S5, VW_CH_IDX2, BIT(2), BIT(6)),
VW_CH(ESPI_VWIRE_SIGNAL_OOB_RST_WARN, VW_CH_IDX3, BIT(2), BIT(6)),
VW_CH(ESPI_VWIRE_SIGNAL_PLTRST, VW_CH_IDX3, BIT(1), BIT(5)),
VW_CH(ESPI_VWIRE_SIGNAL_SUS_STAT, VW_CH_IDX3, BIT(0), BIT(4)),
VW_CH(ESPI_VWIRE_SIGNAL_NMIOUT, VW_CH_IDX7, BIT(2), BIT(6)),
VW_CH(ESPI_VWIRE_SIGNAL_SMIOUT, VW_CH_IDX7, BIT(1), BIT(5)),
VW_CH(ESPI_VWIRE_SIGNAL_HOST_RST_WARN, VW_CH_IDX7, BIT(0), BIT(4)),
VW_CH(ESPI_VWIRE_SIGNAL_SLP_A, VW_CH_IDX41, BIT(3), BIT(7)),
VW_CH(ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK, VW_CH_IDX41, BIT(1), BIT(5)),
VW_CH(ESPI_VWIRE_SIGNAL_SUS_WARN, VW_CH_IDX41, BIT(0), BIT(4)),
VW_CH(ESPI_VWIRE_SIGNAL_SLP_WLAN, VW_CH_IDX42, BIT(1), BIT(5)),
VW_CH(ESPI_VWIRE_SIGNAL_SLP_LAN, VW_CH_IDX42, BIT(0), BIT(4)),
VW_CH(ESPI_VWIRE_SIGNAL_HOST_C10, VW_CH_IDX47, BIT(0), BIT(4)),
VW_CH(ESPI_VWIRE_SIGNAL_DNX_WARN, VW_CH_IDX4A, BIT(1), BIT(5)),
VW_CH(ESPI_VWIRE_SIGNAL_PME, VW_CH_IDX4, BIT(3), BIT(7)),
VW_CH(ESPI_VWIRE_SIGNAL_WAKE, VW_CH_IDX4, BIT(2), BIT(6)),
VW_CH(ESPI_VWIRE_SIGNAL_OOB_RST_ACK, VW_CH_IDX4, BIT(0), BIT(4)),
VW_CH(ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, VW_CH_IDX5, BIT(3), BIT(7)),
VW_CH(ESPI_VWIRE_SIGNAL_ERR_NON_FATAL, VW_CH_IDX5, BIT(2), BIT(6)),
VW_CH(ESPI_VWIRE_SIGNAL_ERR_FATAL, VW_CH_IDX5, BIT(1), BIT(5)),
VW_CH(ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, VW_CH_IDX5, BIT(0), BIT(4)),
VW_CH(ESPI_VWIRE_SIGNAL_HOST_RST_ACK, VW_CH_IDX6, BIT(3), BIT(7)),
VW_CH(ESPI_VWIRE_SIGNAL_RST_CPU_INIT, VW_CH_IDX6, BIT(2), BIT(6)),
VW_CH(ESPI_VWIRE_SIGNAL_SMI, VW_CH_IDX6, BIT(1), BIT(5)),
VW_CH(ESPI_VWIRE_SIGNAL_SCI, VW_CH_IDX6, BIT(0), BIT(4)),
VW_CH(ESPI_VWIRE_SIGNAL_DNX_ACK, VW_CH_IDX40, BIT(1), BIT(5)),
VW_CH(ESPI_VWIRE_SIGNAL_SUS_ACK, VW_CH_IDX40, BIT(0), BIT(4)),
};
struct espi_vw_ch_cached {
uint8_t idx2;
uint8_t idx3;
uint8_t idx7;
uint8_t idx41;
uint8_t idx42;
uint8_t idx43;
uint8_t idx44;
uint8_t idx47;
uint8_t idx4a;
uint8_t idx51;
uint8_t idx61;
};
struct espi_vw_tx_cached {
uint8_t idx4;
uint8_t idx5;
uint8_t idx6;
uint8_t idx40;
};
static struct espi_vw_ch_cached espi_vw_ch_cached_data;
static struct espi_vw_tx_cached espi_vw_tx_cached_data;
static int espi_rts5912_send_vwire(const struct device *dev, enum espi_vwire_signal signal,
uint8_t level);
static int espi_rts5912_receive_vwire(const struct device *dev, enum espi_vwire_signal signal,
uint8_t *level);
static int vw_signal_set_valid(const struct device *dev, enum espi_vwire_signal signal,
uint8_t valid);
static void notify_system_state(const struct device *dev, enum espi_vwire_signal signal);
static void notify_host_warning(const struct device *dev, enum espi_vwire_signal signal);
static void vw_slp3_handler(const struct device *dev);
static void vw_slp4_handler(const struct device *dev);
static void vw_slp5_handler(const struct device *dev);
static void vw_sus_stat_handler(const struct device *dev);
static void vw_pltrst_handler(const struct device *dev);
static void vw_oob_rst_warn_handler(const struct device *dev);
static void vw_host_rst_warn_handler(const struct device *dev);
static void vw_smiout_handler(const struct device *dev);
static void vw_nmiout_handler(const struct device *dev);
static void vw_sus_warn_handler(const struct device *dev);
static void vw_sus_pwrdn_ack_handler(const struct device *dev);
static void vw_sus_slp_a_handler(const struct device *dev);
static void vw_slp_lan_handler(const struct device *dev);
static void vw_slp_wlan_handler(const struct device *dev);
static void vw_host_c10_handler(const struct device *dev);
static void espi_vw_ch_setup(const struct device *dev);
static void espi_vw_ch_isr(const struct device *dev);
#ifdef CONFIG_ESPI_AUTOMATIC_BOOT_DONE_ACKNOWLEDGE
static void send_target_bootdone(const struct device *dev);
#endif
static void espi_vw_ch_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *data = dev->data;
struct espi_event evt = {.evt_type = ESPI_BUS_EVENT_CHANNEL_READY,
.evt_details = ESPI_CHANNEL_VWIRE,
.evt_data = 0};
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint32_t config = espi_reg->EVCFG;
evt.evt_data = (config & ESPI_EVCFG_CHEN) ? 1 : 0;
espi_send_callbacks(&data->callbacks, dev, evt);
if (config & ESPI_EVCFG_CHEN) {
vw_signal_set_valid(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, 1);
vw_signal_set_valid(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, 1);
#ifdef CONFIG_ESPI_AUTOMATIC_BOOT_DONE_ACKNOWLEDGE
send_target_bootdone(dev);
#endif
}
espi_reg->EVSTS = ESPI_EVSTS_RXIDXCHG;
}
static const struct espi_vw_signal_t vw_idx2_signals[] = {
{ESPI_VWIRE_SIGNAL_SLP_S3, vw_slp3_handler},
{ESPI_VWIRE_SIGNAL_SLP_S4, vw_slp4_handler},
{ESPI_VWIRE_SIGNAL_SLP_S5, vw_slp5_handler},
};
static void espi_vw_idx2_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint8_t cur_idx_data = espi_reg->EVIDX2;
uint8_t updated_bit = cur_idx_data ^ espi_vw_ch_cached_data.idx2;
if (espi_reg->EVSTS & ESPI_EVSTS_IDX2CHG) {
espi_vw_ch_cached_data.idx2 = cur_idx_data;
for (int i = 0; i < ARRAY_SIZE(vw_idx2_signals); i++) {
enum espi_vwire_signal vw_signal = vw_idx2_signals[i].signal;
if (updated_bit & vw_channel_list[vw_signal].level_mask &&
vw_idx2_signals[i].vw_signal_callback != NULL) {
vw_idx2_signals[i].vw_signal_callback(dev);
}
}
if (espi_vw_ch_cached_data.idx2 == espi_reg->EVIDX2) {
espi_reg->EVSTS = ESPI_EVSTS_IDX2CHG;
}
}
}
static const struct espi_vw_signal_t vw_idx3_signals[] = {
{ESPI_VWIRE_SIGNAL_SUS_STAT, vw_sus_stat_handler},
{ESPI_VWIRE_SIGNAL_PLTRST, vw_pltrst_handler},
{ESPI_VWIRE_SIGNAL_OOB_RST_WARN, vw_oob_rst_warn_handler},
};
static void espi_vw_idx3_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint8_t cur_idx_data = espi_reg->EVIDX3;
uint8_t updated_bit = cur_idx_data ^ espi_vw_ch_cached_data.idx3;
if (espi_reg->EVSTS & ESPI_EVSTS_IDX3CHG) {
espi_vw_ch_cached_data.idx3 = cur_idx_data;
for (int i = 0; i < ARRAY_SIZE(vw_idx3_signals); i++) {
enum espi_vwire_signal vw_signal = vw_idx3_signals[i].signal;
if (updated_bit & vw_channel_list[vw_signal].level_mask &&
vw_idx3_signals[i].vw_signal_callback != NULL) {
vw_idx3_signals[i].vw_signal_callback(dev);
}
}
if (espi_vw_ch_cached_data.idx3 == espi_reg->EVIDX3) {
espi_reg->EVSTS = ESPI_EVSTS_IDX3CHG;
}
}
}
static const struct espi_vw_signal_t vw_idx7_signals[] = {
{ESPI_VWIRE_SIGNAL_HOST_RST_WARN, vw_host_rst_warn_handler},
{ESPI_VWIRE_SIGNAL_SMIOUT, vw_smiout_handler},
{ESPI_VWIRE_SIGNAL_NMIOUT, vw_nmiout_handler},
};
static void espi_vw_idx7_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint8_t cur_idx_data = espi_reg->EVIDX7;
uint8_t updated_bit = cur_idx_data ^ espi_vw_ch_cached_data.idx7;
if (espi_reg->EVSTS & ESPI_EVSTS_IDX7CHG) {
espi_vw_ch_cached_data.idx7 = cur_idx_data;
for (int i = 0; i < ARRAY_SIZE(vw_idx7_signals); i++) {
enum espi_vwire_signal vw_signal = vw_idx7_signals[i].signal;
if (updated_bit & vw_channel_list[vw_signal].level_mask &&
vw_idx7_signals[i].vw_signal_callback != NULL) {
vw_idx7_signals[i].vw_signal_callback(dev);
}
}
if (espi_vw_ch_cached_data.idx7 == espi_reg->EVIDX7) {
espi_reg->EVSTS = ESPI_EVSTS_IDX7CHG;
}
}
}
static const struct espi_vw_signal_t vw_idx41_signals[] = {
{ESPI_VWIRE_SIGNAL_SUS_WARN, vw_sus_warn_handler},
{ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK, vw_sus_pwrdn_ack_handler},
{ESPI_VWIRE_SIGNAL_SLP_A, vw_sus_slp_a_handler},
};
static void espi_vw_idx41_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint8_t cur_idx_data = espi_reg->EVIDX41;
uint8_t updated_bit = cur_idx_data ^ espi_vw_ch_cached_data.idx41;
if (espi_reg->EVSTS & ESPI_EVSTS_IDX41CHG) {
espi_vw_ch_cached_data.idx41 = cur_idx_data;
for (int i = 0; i < ARRAY_SIZE(vw_idx41_signals); i++) {
enum espi_vwire_signal vw_signal = vw_idx41_signals[i].signal;
if (updated_bit & vw_channel_list[vw_signal].level_mask &&
vw_idx41_signals[i].vw_signal_callback != NULL) {
vw_idx41_signals[i].vw_signal_callback(dev);
}
}
if (espi_vw_ch_cached_data.idx41 == espi_reg->EVIDX41) {
espi_reg->EVSTS = ESPI_EVSTS_IDX41CHG;
}
}
}
static const struct espi_vw_signal_t vw_idx42_signals[] = {
{ESPI_VWIRE_SIGNAL_SLP_LAN, vw_slp_lan_handler},
{ESPI_VWIRE_SIGNAL_SLP_WLAN, vw_slp_wlan_handler},
};
static void espi_vw_idx42_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint8_t cur_idx_data = espi_reg->EVIDX42;
uint8_t updated_bit = cur_idx_data ^ espi_vw_ch_cached_data.idx42;
if (espi_reg->EVSTS & ESPI_EVSTS_IDX42CHG) {
espi_vw_ch_cached_data.idx42 = cur_idx_data;
for (int i = 0; i < ARRAY_SIZE(vw_idx42_signals); i++) {
enum espi_vwire_signal vw_signal = vw_idx42_signals[i].signal;
if (updated_bit & vw_channel_list[vw_signal].level_mask &&
vw_idx42_signals[i].vw_signal_callback != NULL) {
vw_idx42_signals[i].vw_signal_callback(dev);
}
}
if (espi_vw_ch_cached_data.idx42 == espi_reg->EVIDX42) {
espi_reg->EVSTS = ESPI_EVSTS_IDX42CHG;
}
}
}
static const struct espi_vw_signal_t vw_idx43_signals[] = {};
static void espi_vw_idx43_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint8_t cur_idx_data = espi_reg->EVIDX43;
uint8_t updated_bit = cur_idx_data ^ espi_vw_ch_cached_data.idx43;
if (espi_reg->EVSTS & ESPI_EVSTS_IDX43CHG) {
espi_vw_ch_cached_data.idx43 = cur_idx_data;
for (int i = 0; i < ARRAY_SIZE(vw_idx43_signals); i++) {
enum espi_vwire_signal vw_signal = vw_idx43_signals[i].signal;
if (updated_bit & vw_channel_list[vw_signal].level_mask &&
vw_idx43_signals[i].vw_signal_callback != NULL) {
vw_idx43_signals[i].vw_signal_callback(dev);
}
}
if (espi_vw_ch_cached_data.idx43 == espi_reg->EVIDX43) {
espi_reg->EVSTS = ESPI_EVSTS_IDX43CHG;
}
}
}
static const struct espi_vw_signal_t vw_idx44_signals[] = {};
static void espi_vw_idx44_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint8_t cur_idx_data = espi_reg->EVIDX44;
uint8_t updated_bit = cur_idx_data ^ espi_vw_ch_cached_data.idx44;
if (espi_reg->EVSTS & ESPI_EVSTS_IDX44CHG) {
espi_vw_ch_cached_data.idx44 = cur_idx_data;
for (int i = 0; i < ARRAY_SIZE(vw_idx44_signals); i++) {
enum espi_vwire_signal vw_signal = vw_idx44_signals[i].signal;
if (updated_bit & vw_channel_list[vw_signal].level_mask &&
vw_idx44_signals[i].vw_signal_callback != NULL) {
vw_idx44_signals[i].vw_signal_callback(dev);
}
}
if (espi_vw_ch_cached_data.idx44 == espi_reg->EVIDX44) {
espi_reg->EVSTS = ESPI_EVSTS_IDX44CHG;
}
}
}
static const struct espi_vw_signal_t vw_idx47_signals[] = {
{ESPI_VWIRE_SIGNAL_HOST_C10, vw_host_c10_handler},
};
static void espi_vw_idx47_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint8_t cur_idx_data = espi_reg->EVIDX47;
uint8_t updated_bit = cur_idx_data ^ espi_vw_ch_cached_data.idx47;
if (espi_reg->EVSTS & ESPI_EVSTS_IDX47CHG) {
espi_vw_ch_cached_data.idx47 = cur_idx_data;
for (int i = 0; i < ARRAY_SIZE(vw_idx47_signals); i++) {
enum espi_vwire_signal vw_signal = vw_idx47_signals[i].signal;
if (updated_bit & vw_channel_list[vw_signal].level_mask &&
vw_idx47_signals[i].vw_signal_callback != NULL) {
vw_idx47_signals[i].vw_signal_callback(dev);
}
}
if (espi_vw_ch_cached_data.idx47 == espi_reg->EVIDX47) {
espi_reg->EVSTS = ESPI_EVSTS_IDX47CHG;
}
}
}
static void espi_vw_idx4a_isr(const struct device *dev)
{
ARG_UNUSED(dev);
}
static void espi_vw_idx51_isr(const struct device *dev)
{
ARG_UNUSED(dev);
}
static void espi_vw_idx61_isr(const struct device *dev)
{
ARG_UNUSED(dev);
}
static int vw_signal_set_valid(const struct device *dev, enum espi_vwire_signal signal,
uint8_t valid)
{
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;
}
switch (vw_index) {
case VW_CH_IDX4:
if (valid) {
espi_vw_tx_cached_data.idx4 |= valid_mask;
} else {
espi_vw_tx_cached_data.idx4 &= ~valid_mask;
}
break;
case VW_CH_IDX5:
if (valid) {
espi_vw_tx_cached_data.idx5 |= valid_mask;
} else {
espi_vw_tx_cached_data.idx5 &= ~valid_mask;
}
break;
case VW_CH_IDX6:
if (valid) {
espi_vw_tx_cached_data.idx6 |= valid_mask;
} else {
espi_vw_tx_cached_data.idx6 &= ~valid_mask;
}
break;
case VW_CH_IDX40:
if (valid) {
espi_vw_tx_cached_data.idx40 |= valid_mask;
} else {
espi_vw_tx_cached_data.idx40 &= ~valid_mask;
}
break;
default:
return -EIO;
}
return 0;
}
static void vw_ch_isr_wa_cb(struct k_work *work)
{
espi_vw_ch_isr(DEVICE_DT_GET(DT_DRV_INST(0)));
}
static K_WORK_DELAYABLE_DEFINE(vw_ch_isr_wa, vw_ch_isr_wa_cb);
#ifdef CONFIG_ESPI_AUTOMATIC_BOOT_DONE_ACKNOWLEDGE
static void send_target_bootdone(const struct device *dev)
{
int ret;
uint8_t boot_done;
ret = espi_rts5912_receive_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, &boot_done);
if (!ret && !boot_done) {
espi_rts5912_send_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, 1);
espi_rts5912_send_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, 1);
k_work_cancel_delayable(&vw_ch_isr_wa);
}
}
#endif
static void notify_system_state(const struct device *dev, enum espi_vwire_signal signal)
{
struct espi_rts5912_data *data = dev->data;
struct espi_event evt = {ESPI_BUS_EVENT_VWIRE_RECEIVED, 0, 0};
uint8_t status = 0;
espi_rts5912_receive_vwire(dev, signal, &status);
evt.evt_details = signal;
evt.evt_data = status;
espi_send_callbacks(&data->callbacks, dev, evt);
}
static void notify_host_warning(const struct device *dev, enum espi_vwire_signal signal)
{
uint8_t status = 0;
espi_rts5912_receive_vwire(dev, signal, &status);
k_busy_wait(200);
switch (signal) {
case ESPI_VWIRE_SIGNAL_SUS_WARN:
vw_signal_set_valid(dev, ESPI_VWIRE_SIGNAL_SUS_ACK, 1);
espi_rts5912_send_vwire(dev, ESPI_VWIRE_SIGNAL_SUS_ACK, status);
break;
case ESPI_VWIRE_SIGNAL_OOB_RST_WARN:
espi_rts5912_send_vwire(dev, ESPI_VWIRE_SIGNAL_OOB_RST_ACK, status);
break;
case ESPI_VWIRE_SIGNAL_HOST_RST_WARN:
espi_rts5912_send_vwire(dev, ESPI_VWIRE_SIGNAL_HOST_RST_ACK, status);
break;
default:
break;
}
}
static void vw_slp3_handler(const struct device *dev)
{
notify_system_state(dev, ESPI_VWIRE_SIGNAL_SLP_S3);
}
static void vw_slp4_handler(const struct device *dev)
{
notify_system_state(dev, ESPI_VWIRE_SIGNAL_SLP_S4);
}
static void vw_slp5_handler(const struct device *dev)
{
notify_system_state(dev, ESPI_VWIRE_SIGNAL_SLP_S5);
}
static void vw_sus_stat_handler(const struct device *dev)
{
notify_system_state(dev, ESPI_VWIRE_SIGNAL_SUS_STAT);
}
static void vw_pltrst_handler(const struct device *dev)
{
struct espi_rts5912_data *data = dev->data;
struct espi_event evt = {ESPI_BUS_EVENT_VWIRE_RECEIVED, ESPI_VWIRE_SIGNAL_PLTRST, 0};
uint8_t status = 0;
espi_rts5912_receive_vwire(dev, ESPI_VWIRE_SIGNAL_PLTRST, &status);
if (status) {
vw_signal_set_valid(dev, ESPI_VWIRE_SIGNAL_SMI, 1);
vw_signal_set_valid(dev, ESPI_VWIRE_SIGNAL_SCI, 1);
vw_signal_set_valid(dev, ESPI_VWIRE_SIGNAL_HOST_RST_ACK, 1);
vw_signal_set_valid(dev, ESPI_VWIRE_SIGNAL_RST_CPU_INIT, 1);
espi_rts5912_send_vwire(dev, ESPI_VWIRE_SIGNAL_SMI, 1);
espi_rts5912_send_vwire(dev, ESPI_VWIRE_SIGNAL_SCI, 1);
espi_rts5912_send_vwire(dev, ESPI_VWIRE_SIGNAL_HOST_RST_ACK, 1);
espi_rts5912_send_vwire(dev, ESPI_VWIRE_SIGNAL_RST_CPU_INIT, 1);
}
evt.evt_data = status;
espi_send_callbacks(&data->callbacks, dev, evt);
}
static void vw_oob_rst_warn_handler(const struct device *dev)
{
if (!IS_ENABLED(CONFIG_ESPI_AUTOMATIC_WARNING_ACKNOWLEDGE)) {
notify_system_state(dev, ESPI_VWIRE_SIGNAL_OOB_RST_WARN);
} else {
notify_host_warning(dev, ESPI_VWIRE_SIGNAL_OOB_RST_WARN);
}
}
static void vw_host_rst_warn_handler(const struct device *dev)
{
if (!IS_ENABLED(CONFIG_ESPI_AUTOMATIC_WARNING_ACKNOWLEDGE)) {
notify_system_state(dev, ESPI_VWIRE_SIGNAL_HOST_RST_WARN);
} else {
notify_host_warning(dev, ESPI_VWIRE_SIGNAL_HOST_RST_WARN);
}
}
static void vw_smiout_handler(const struct device *dev)
{
notify_system_state(dev, ESPI_VWIRE_SIGNAL_SMIOUT);
}
static void vw_nmiout_handler(const struct device *dev)
{
notify_system_state(dev, ESPI_VWIRE_SIGNAL_NMIOUT);
}
static void vw_sus_warn_handler(const struct device *dev)
{
if (!IS_ENABLED(CONFIG_ESPI_AUTOMATIC_WARNING_ACKNOWLEDGE)) {
notify_system_state(dev, ESPI_VWIRE_SIGNAL_SUS_WARN);
} else {
notify_host_warning(dev, ESPI_VWIRE_SIGNAL_SUS_WARN);
}
}
static void vw_sus_pwrdn_ack_handler(const struct device *dev)
{
notify_system_state(dev, ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK);
}
static void vw_sus_slp_a_handler(const struct device *dev)
{
notify_system_state(dev, ESPI_VWIRE_SIGNAL_SLP_A);
}
static void vw_slp_lan_handler(const struct device *dev)
{
notify_system_state(dev, ESPI_VWIRE_SIGNAL_SLP_LAN);
}
static void vw_slp_wlan_handler(const struct device *dev)
{
notify_system_state(dev, ESPI_VWIRE_SIGNAL_SLP_WLAN);
}
static void vw_host_c10_handler(const struct device *dev)
{
notify_system_state(dev, ESPI_VWIRE_SIGNAL_HOST_C10);
}
#define VW_TIMEOUT_US 1000
static int espi_rts5912_send_vwire(const struct device *dev, enum espi_vwire_signal signal,
uint8_t level)
{
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint8_t vw_idx = vw_channel_list[signal].vw_index;
uint8_t lev_msk = vw_channel_list[signal].level_mask;
uint32_t tx_data = 0;
if (signal > ARRAY_SIZE(vw_channel_list)) {
return -EIO;
}
switch (vw_idx) {
case VW_CH_IDX4:
tx_data = espi_vw_tx_cached_data.idx4;
break;
case VW_CH_IDX5:
tx_data = espi_vw_tx_cached_data.idx5;
break;
case VW_CH_IDX6:
tx_data = espi_vw_tx_cached_data.idx6;
break;
case VW_CH_IDX40:
tx_data = espi_vw_tx_cached_data.idx40;
break;
default:
return -EIO;
}
tx_data |= (vw_idx << 8);
if (level) {
tx_data |= lev_msk;
} else {
tx_data &= ~lev_msk;
}
if (espi_reg->EVSTS & ESPI_EVSTS_TXFULL) {
return -EIO;
}
espi_reg->EVTXDAT = tx_data;
WAIT_FOR(!(espi_reg->EVSTS & ESPI_EVSTS_TXFULL), VW_TIMEOUT_US, k_busy_wait(10));
switch (vw_idx) {
case VW_CH_IDX4:
espi_vw_tx_cached_data.idx4 = tx_data;
break;
case VW_CH_IDX5:
espi_vw_tx_cached_data.idx5 = tx_data;
break;
case VW_CH_IDX6:
espi_vw_tx_cached_data.idx6 = tx_data;
break;
case VW_CH_IDX40:
espi_vw_tx_cached_data.idx40 = tx_data;
break;
default:
return -EIO;
}
return 0;
}
static int espi_rts5912_receive_vwire(const struct device *dev, enum espi_vwire_signal signal,
uint8_t *level)
{
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint8_t vw_idx, lev_msk, valid_msk;
uint8_t vw_data;
vw_idx = vw_channel_list[signal].vw_index;
lev_msk = vw_channel_list[signal].level_mask;
valid_msk = vw_channel_list[signal].valid_mask;
if (signal > ARRAY_SIZE(vw_channel_list)) {
return -EIO;
}
switch (vw_idx) {
case VW_CH_IDX2:
vw_data = espi_vw_ch_cached_data.idx2;
break;
case VW_CH_IDX3:
if (espi_vw_ch_cached_data.idx3 != espi_reg->EVIDX3) {
espi_vw_ch_cached_data.idx3 = espi_reg->EVIDX3;
}
vw_data = espi_vw_ch_cached_data.idx3;
break;
case VW_CH_IDX4:
vw_data = espi_vw_tx_cached_data.idx4;
break;
case VW_CH_IDX5:
vw_data = espi_vw_tx_cached_data.idx5;
break;
case VW_CH_IDX6:
vw_data = espi_vw_tx_cached_data.idx6;
break;
case VW_CH_IDX7:
if (espi_vw_ch_cached_data.idx7 != espi_reg->EVIDX7) {
espi_vw_ch_cached_data.idx7 = espi_reg->EVIDX7;
}
vw_data = espi_vw_ch_cached_data.idx7;
break;
case VW_CH_IDX40:
vw_data = espi_vw_tx_cached_data.idx40;
break;
case VW_CH_IDX41:
if (espi_vw_ch_cached_data.idx41 != espi_reg->EVIDX41) {
espi_vw_ch_cached_data.idx41 = espi_reg->EVIDX41;
}
vw_data = espi_vw_ch_cached_data.idx41;
break;
case VW_CH_IDX42:
if (espi_vw_ch_cached_data.idx42 != espi_reg->EVIDX42) {
espi_vw_ch_cached_data.idx42 = espi_reg->EVIDX42;
}
vw_data = espi_vw_ch_cached_data.idx42;
break;
case VW_CH_IDX43:
if (espi_vw_ch_cached_data.idx43 != espi_reg->EVIDX43) {
espi_vw_ch_cached_data.idx43 = espi_reg->EVIDX43;
}
vw_data = espi_vw_ch_cached_data.idx43;
break;
case VW_CH_IDX44:
if (espi_vw_ch_cached_data.idx44 != espi_reg->EVIDX44) {
espi_vw_ch_cached_data.idx44 = espi_reg->EVIDX44;
}
vw_data = espi_vw_ch_cached_data.idx44;
break;
case VW_CH_IDX47:
if (espi_vw_ch_cached_data.idx47 != espi_reg->EVIDX47) {
espi_vw_ch_cached_data.idx47 = espi_reg->EVIDX47;
}
vw_data = espi_vw_ch_cached_data.idx47;
break;
case VW_CH_IDX4A:
if (espi_vw_ch_cached_data.idx4a != espi_reg->EVIDX4A) {
espi_vw_ch_cached_data.idx4a = espi_reg->EVIDX4A;
}
vw_data = espi_vw_ch_cached_data.idx4a;
break;
case VW_CH_IDX51:
if (espi_vw_ch_cached_data.idx51 != espi_reg->EVIDX51) {
espi_vw_ch_cached_data.idx51 = espi_reg->EVIDX51;
}
vw_data = espi_vw_ch_cached_data.idx51;
break;
case VW_CH_IDX61:
if (espi_vw_ch_cached_data.idx61 != espi_reg->EVIDX61) {
espi_vw_ch_cached_data.idx61 = espi_reg->EVIDX61;
}
vw_data = espi_vw_ch_cached_data.idx61;
break;
default:
return -EIO;
}
if (IS_ENABLED(CONFIG_ESPI_VWIRE_VALID_BIT_CHECK)) {
if (vw_data & valid_msk) {
*level = !!(vw_data & lev_msk);
} else {
/* Not valid */
*level = 0;
}
} else {
*level = !!(vw_data & lev_msk);
}
return 0;
}
static void espi_vw_ch_setup(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
espi_reg->EVSTS |= ESPI_EVSTS_RXIDXCLR;
espi_vw_ch_cached_data.idx2 = espi_reg->EVIDX2;
espi_vw_ch_cached_data.idx3 = espi_reg->EVIDX3;
espi_vw_ch_cached_data.idx7 = espi_reg->EVIDX7;
espi_vw_ch_cached_data.idx41 = espi_reg->EVIDX41;
espi_vw_ch_cached_data.idx42 = espi_reg->EVIDX42;
espi_vw_ch_cached_data.idx43 = espi_reg->EVIDX43;
espi_vw_ch_cached_data.idx44 = espi_reg->EVIDX44;
espi_vw_ch_cached_data.idx47 = espi_reg->EVIDX47;
espi_vw_ch_cached_data.idx4a = espi_reg->EVIDX4A;
espi_vw_ch_cached_data.idx51 = espi_reg->EVIDX51;
espi_vw_ch_cached_data.idx61 = espi_reg->EVIDX61;
espi_vw_tx_cached_data.idx4 = 0;
espi_vw_tx_cached_data.idx5 = 0;
espi_vw_tx_cached_data.idx6 = 0;
espi_vw_tx_cached_data.idx40 = 0;
espi_reg->EVRXINTEN = (ESPI_EVRXINTEN_CFGCHGEN | ESPI_EVRXINTEN_RXCHGEN);
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_ch, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx2, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx3, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx7, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx41, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx42, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx43, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx44, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx47, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx4a, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx51, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx61, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_ch, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_ch, priority), espi_vw_ch_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_ch, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx2, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx2, priority), espi_vw_idx2_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx2, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx3, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx3, priority), espi_vw_idx3_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx3, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx7, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx7, priority), espi_vw_idx7_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx7, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx41, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx41, priority), espi_vw_idx41_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx41, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx42, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx42, priority), espi_vw_idx42_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx42, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx43, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx43, priority), espi_vw_idx43_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx43, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx44, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx44, priority), espi_vw_idx44_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx44, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx47, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx47, priority), espi_vw_idx47_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx47, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx4a, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx4a, priority), espi_vw_idx4a_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx4a, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx51, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx51, priority), espi_vw_idx51_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx51, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx61, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx61, priority), espi_vw_idx61_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx61, irq));
}
#endif /* CONFIG_ESPI_VWIRE_CHANNEL */
/*
* =========================================================================
* ESPI OOB channel
@ -196,6 +1081,11 @@ static void espi_oob_chg_isr(const struct device *dev)
if (status & ESPI_EOSTS_CFGENCHG) {
evt.evt_data = config & ESPI_EVCFG_CHEN ? 1 : 0;
espi_send_callbacks(&espi_data->callbacks, dev, evt);
if (config & ESPI_EVCFG_CHEN) {
vw_signal_set_valid(dev, ESPI_VWIRE_SIGNAL_OOB_RST_ACK, 1);
}
espi_reg->EOSTS = ESPI_EOSTS_CFGENCHG;
}
}
@ -574,6 +1464,10 @@ static DEVICE_API(espi, espi_rts5912_driver_api) = {
.config = espi_rts5912_configure,
.get_channel_status = espi_rts5912_channel_ready,
.manage_callback = espi_rts5912_manage_callback,
#ifdef CONFIG_ESPI_VWIRE_CHANNEL
.send_vwire = espi_rts5912_send_vwire,
.receive_vwire = espi_rts5912_receive_vwire,
#endif
#ifdef CONFIG_ESPI_OOB_CHANNEL
.send_oob = espi_rts5912_send_oob,
.receive_oob = espi_rts5912_receive_oob,
@ -585,6 +1479,10 @@ static DEVICE_API(espi, espi_rts5912_driver_api) = {
#endif
};
static void espi_vw_ch_setup(const struct device *dev);
#define VW_RESET_DELAY 150UL
static void espi_rst_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
@ -605,6 +1503,15 @@ static void espi_rst_isr(const struct device *dev)
} else {
/* rst pin low go high trigger interrupt */
evt.evt_data = 1;
#ifdef CONFIG_ESPI_VWIRE_CHANNEL
espi_vw_ch_setup(dev);
espi_reg->ESPICFG = data->config_data;
if (espi_reg->EVCFG & ESPI_EVCFG_CHEN) {
k_timeout_t delay = K_MSEC(VW_RESET_DELAY);
k_work_schedule(&vw_ch_isr_wa, delay);
}
#endif
}
espi_send_callbacks(&data->callbacks, dev, evt);
}
@ -666,6 +1573,11 @@ static int espi_rts5912_init(const struct device *dev)
/* Setup eSPI bus reset */
espi_bus_reset_setup(dev);
#ifdef CONFIG_ESPI_VWIRE_CHANNEL
/* Setup eSPI virtual-wire channel */
espi_vw_ch_setup(dev);
#endif
#ifdef CONFIG_ESPI_OOB_CHANNEL
/* Setup eSPI OOB channel */
rc = espi_oob_ch_setup(dev);