Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2443 lines
72 KiB

/*
* Copyright (c) 2025 Realtek, SIBG-SD7
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT realtek_rts5912_espi
#include <zephyr/kernel.h>
#include <zephyr/drivers/espi.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/clock_control/clock_control_rts5912.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(espi, CONFIG_ESPI_LOG_LEVEL);
#include "espi_utils.h"
#include "reg/reg_acpi.h"
#include "reg/reg_emi.h"
#include "reg/reg_espi.h"
#include "reg/reg_kbc.h"
#include "reg/reg_port80.h"
BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "support only one espi compatible node");
struct espi_rts5912_config {
volatile struct espi_reg *const espi_reg;
uint32_t espislv_clk_grp;
uint32_t espislv_clk_idx;
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
volatile struct kbc_reg *const kbc_reg;
uint32_t kbc_clk_grp;
uint32_t kbc_clk_idx;
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO
volatile struct acpi_reg *const acpi_reg;
uint32_t acpi_clk_grp;
uint32_t acpi_clk_idx;
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD
volatile struct acpi_reg *const promt0_reg;
uint32_t promt0_clk_grp;
uint32_t promt0_clk_idx;
volatile struct emi_reg *const emi0_reg;
uint32_t emi0_clk_grp;
uint32_t emi0_clk_idx;
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION
volatile struct emi_reg *const emi1_reg;
uint32_t emi1_clk_grp;
uint32_t emi1_clk_idx;
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80
volatile struct port80_reg *const port80_reg;
uint32_t port80_clk_grp;
uint32_t port80_clk_idx;
#endif
const struct device *clk_dev;
const struct pinctrl_dev_config *pcfg;
};
struct espi_rts5912_data {
sys_slist_t callbacks;
uint32_t config_data;
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
int kbc_int_en;
int kbc_pre_irq1;
#endif
#ifdef CONFIG_ESPI_OOB_CHANNEL
struct k_sem oob_rx_lock;
struct k_sem oob_tx_lock;
uint8_t *oob_tx_ptr;
uint8_t *oob_rx_ptr;
bool oob_tx_busy;
#endif
#ifdef CONFIG_ESPI_FLASH_CHANNEL
struct k_sem flash_lock;
uint8_t *maf_ptr;
#endif
};
/*
* =========================================================================
* ESPI Peripheral KBC
* =========================================================================
*/
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
static int espi_send_vw_event(uint8_t index, uint8_t data, const struct device *dev);
static void kbc_ibf_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
struct espi_event evt = {
ESPI_BUS_PERIPHERAL_NOTIFICATION,
ESPI_PERIPHERAL_8042_KBC,
ESPI_PERIPHERAL_NODATA,
};
volatile struct kbc_reg *const kbc_reg = espi_config->kbc_reg;
struct espi_evt_data_kbc *kbc_evt = (struct espi_evt_data_kbc *)&evt.evt_data;
/*
* Indicates if the host sent a command or data.
* 0 = data
* 1 = Command.
*/
kbc_evt->type = kbc_reg->STS & KBC_STS_CMDSEL ? 1 : 0;
/* The data in KBC Input Buffer */
kbc_evt->data = kbc_reg->IB;
/* KBC Input Buffer Full event */
kbc_evt->evt = HOST_KBC_EVT_IBF;
espi_send_callbacks(&espi_data->callbacks, dev, evt);
}
static void kbc_obe_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
struct espi_event evt = {
ESPI_BUS_PERIPHERAL_NOTIFICATION,
ESPI_PERIPHERAL_8042_KBC,
ESPI_PERIPHERAL_NODATA,
};
volatile struct kbc_reg *const kbc_reg = espi_config->kbc_reg;
struct espi_evt_data_kbc *kbc_evt = (struct espi_evt_data_kbc *)&evt.evt_data;
if (espi_data->kbc_pre_irq1 == 1 && !espi_send_vw_event(0x0, 0x01, dev)) {
espi_data->kbc_pre_irq1 = 0;
}
if (kbc_reg->STS & KBC_STS_OBF) {
kbc_reg->OB |= KBC_OB_OBCLR;
}
/* Notify application that host already read out data. */
kbc_evt->type = 0;
kbc_evt->data = 0;
kbc_evt->evt = HOST_KBC_EVT_OBE;
espi_send_callbacks(&espi_data->callbacks, dev, evt);
}
static int espi_kbc_setup(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *const espi_data = dev->data;
struct rts5912_sccon_subsys sccon;
volatile struct kbc_reg *const kbc_reg = espi_config->kbc_reg;
int rc;
if (!device_is_ready(espi_config->clk_dev)) {
LOG_ERR("KBC clock not ready");
return -ENODEV;
}
espi_data->kbc_int_en = 1;
espi_data->kbc_pre_irq1 = 0;
sccon.clk_grp = espi_config->kbc_clk_grp;
sccon.clk_idx = espi_config->kbc_clk_idx;
rc = clock_control_on(espi_config->clk_dev, (clock_control_subsys_t)&sccon);
if (rc != 0) {
LOG_ERR("KBC clock control on failed");
return rc;
}
kbc_reg->VWCTRL1 = (0x01 << KBC_VWCTRL1_IRQNUM_Pos) | KBC_VWCTRL1_ACTEN;
kbc_reg->INTEN = KBC_INTEN_IBFINTEN | KBC_INTEN_OBFINTEN;
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_ibf, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_obe, irq));
/* IBF */
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_ibf, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_ibf, priority), kbc_ibf_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_ibf, irq));
/* OBE */
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_obe, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_obe, priority), kbc_obe_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_obe, irq));
return 0;
}
static int lpc_request_read_8042(const struct device *dev, enum lpc_peripheral_opcode op,
uint32_t *data)
{
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct kbc_reg *const kbc_reg = espi_config->kbc_reg;
switch (op) {
case E8042_OBF_HAS_CHAR:
*data = (kbc_reg->STS & KBC_STS_OBF) ? 1 : 0;
break;
case E8042_IBF_HAS_CHAR:
*data = (kbc_reg->STS & KBC_STS_IBF) ? 1 : 0;
break;
case E8042_READ_KB_STS:
*data = kbc_reg->STS;
break;
default:
return -EINVAL;
}
return 0;
}
static int espi_send_vw_event(uint8_t index, uint8_t data, const struct device *dev);
static void espi_send_vw_event_with_kbdata(uint8_t index, uint8_t data, uint32_t kbc_data,
const struct device *dev);
static uint8_t kbc_write(uint8_t data, const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
const struct espi_rts5912_data *const espi_data = dev->data;
volatile struct kbc_reg *const kbc_reg = espi_config->kbc_reg;
uint32_t exData = (uint32_t)data;
if (espi_data->kbc_pre_irq1 == 1) {
/* Gen IRQ1-Level High to VW ch */
espi_send_vw_event(0x0, 0x01, dev);
}
if (espi_data->kbc_int_en) {
/* Gen IRQ1-Level High to VW ch */
espi_send_vw_event_with_kbdata(0x0, 0x81, exData, dev);
} else {
kbc_reg->OB = exData;
}
return 0;
}
static int lpc_request_write_8042(const struct device *dev, enum lpc_peripheral_opcode op,
uint32_t *data)
{
struct espi_rts5912_data *const espi_data = dev->data;
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct kbc_reg *const kbc_reg = espi_config->kbc_reg;
switch (op) {
case E8042_WRITE_KB_CHAR:
kbc_write(*data & 0xff, dev);
break;
case E8042_WRITE_MB_CHAR:
kbc_write(*data & 0xff, dev);
break;
case E8042_RESUME_IRQ:
espi_data->kbc_int_en = 1;
break;
case E8042_PAUSE_IRQ:
espi_data->kbc_int_en = 0;
break;
case E8042_CLEAR_OBF:
kbc_reg->OB |= KBC_OB_OBCLR;
break;
case E8042_SET_FLAG:
/* FW shouldn't modify these flags directly */
*data &= ~(KBC_STS_OBF | KBC_STS_IBF | KBC_STS_STS2);
kbc_reg->STS |= *data & 0xff;
break;
case E8042_CLEAR_FLAG:
/* FW shouldn't modify these flags directly */
*data |= KBC_STS_OBF | KBC_STS_IBF | KBC_STS_STS2;
kbc_reg->STS &= ~(*data & 0xff);
break;
default:
return -EINVAL;
}
return 0;
}
#else /* CONFIG_ESPI_PERIPHERAL_8042_KBC */
static int lpc_request_read_8042(const struct device *dev, enum lpc_peripheral_opcode op,
uint32_t *data)
{
return -ENOTSUP;
}
static int lpc_request_write_8042(const struct device *dev, enum lpc_peripheral_opcode op,
uint32_t *data)
{
return -ENOTSUP;
}
#endif /* CONFIG_ESPI_PERIPHERAL_8042_KBC */
/*
* =========================================================================
* ESPI Peripheral Shared Memory Region
* =========================================================================
*/
#ifdef CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION
#define ESPI_RTK_PERIPHERAL_ACPI_SHD_MEM_SIZE 256
static uint8_t acpi_shd_mem_sram[ESPI_RTK_PERIPHERAL_ACPI_SHD_MEM_SIZE] __aligned(256);
static void espi_setup_acpi_shm(const struct espi_rts5912_config *const espi_config)
{
volatile struct emi_reg *const emi1_reg = espi_config->emi1_reg;
emi1_reg->SAR = (uint32_t)&acpi_shd_mem_sram[0];
}
#endif /* CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION */
/*
* =========================================================================
* ESPI Peripheral Host IO (ACPI)
* =========================================================================
*/
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO
static void acpi_ibf_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
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;
volatile struct acpi_reg *const acpi_reg = espi_config->acpi_reg;
/* Host put data on input buffer of ACPI EC0 channel */
if (acpi_reg->STS & ACPI_STS_IBF) {
/*
* Indicates if the host sent a command or data.
* 0 = data
* 1 = Command.
*/
acpi_evt->type = acpi_reg->STS & ACPI_STS_CMDSEL ? 1 : 0;
acpi_evt->data = (uint8_t)acpi_reg->IB;
}
espi_send_callbacks(&espi_data->callbacks, dev, evt);
}
static int espi_acpi_setup(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct rts5912_sccon_subsys sccon;
volatile struct acpi_reg *const acpi_reg = espi_config->acpi_reg;
int rc;
if (!device_is_ready(espi_config->clk_dev)) {
LOG_ERR("ACPI clock not ready");
return -ENODEV;
}
sccon.clk_grp = espi_config->acpi_clk_grp;
sccon.clk_idx = espi_config->acpi_clk_idx;
rc = clock_control_on(espi_config->clk_dev, (clock_control_subsys_t)&sccon);
if (rc != 0) {
LOG_ERR("ACPI clock control on failed");
return rc;
}
acpi_reg->VWCTRL1 = (0x00UL << ACPI_VWCTRL1_IRQNUM_Pos) | ACPI_VWCTRL1_ACTEN;
acpi_reg->INTEN = ACPI_INTEN_IBFINTEN;
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), acpi_ibf, irq));
/* IBF */
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), acpi_ibf, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), acpi_ibf, priority), acpi_ibf_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), acpi_ibf, irq));
return 0;
}
static int lpc_request_read_acpi(const struct espi_rts5912_config *const espi_config,
enum lpc_peripheral_opcode op, uint32_t *data)
{
volatile struct acpi_reg *const acpi_reg = espi_config->acpi_reg;
switch (op) {
case EACPI_OBF_HAS_CHAR:
*data = acpi_reg->STS & ACPI_STS_OBF ? 1 : 0;
break;
case EACPI_IBF_HAS_CHAR:
*data = acpi_reg->STS & ACPI_STS_IBF ? 1 : 0;
break;
case EACPI_READ_STS:
*data = acpi_reg->STS;
break;
#ifdef CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION
case EACPI_GET_SHARED_MEMORY:
*data = (uint32_t)acpi_shd_mem_sram;
break;
#endif
default:
return -EINVAL;
}
return 0;
}
static int lpc_request_write_acpi(const struct espi_rts5912_config *const espi_config,
enum lpc_peripheral_opcode op, uint32_t *data)
{
volatile struct acpi_reg *const acpi_reg = espi_config->acpi_reg;
switch (op) {
case EACPI_WRITE_CHAR:
acpi_reg->OB = *data & 0xff;
break;
case EACPI_WRITE_STS:
acpi_reg->STS = *data & 0xff;
break;
default:
return -EINVAL;
}
return 0;
}
#else /* CONFIG_ESPI_PERIPHERAL_HOST_IO */
static int lpc_request_read_acpi(const struct espi_rts5912_config *const espi_config,
enum lpc_peripheral_opcode op, uint32_t *data)
{
return -ENOTSUP;
}
static int lpc_request_write_acpi(const struct espi_rts5912_config *const espi_config,
enum lpc_peripheral_opcode op, uint32_t *data)
{
return -ENOTSUP;
}
#endif /* CONFIG_ESPI_PERIPHERAL_HOST_IO */
/*
* =========================================================================
* ESPI Peripheral EC Host Command (Promt0)
* =========================================================================
*/
#ifdef CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD
#define ESPI_RTK_PERIPHERAL_HOST_CMD_PARAM_SIZE 256
static uint8_t ec_host_cmd_sram[ESPI_RTK_PERIPHERAL_HOST_CMD_PARAM_SIZE] __aligned(256);
static void espi_setup_host_cmd_shm(const struct espi_rts5912_config *const espi_config)
{
volatile struct emi_reg *const emi0_reg = espi_config->emi0_reg;
emi0_reg->SAR = (uint32_t)&ec_host_cmd_sram[0];
}
static void promt0_ibf_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct acpi_reg *const promt0_reg = espi_config->promt0_reg;
struct espi_rts5912_data *data = dev->data;
struct espi_event evt = {.evt_type = ESPI_BUS_PERIPHERAL_NOTIFICATION,
.evt_details = ESPI_PERIPHERAL_EC_HOST_CMD,
.evt_data = ESPI_PERIPHERAL_NODATA};
promt0_reg->STS |= ACPI_STS_STS0;
evt.evt_data = (uint8_t)promt0_reg->IB;
espi_send_callbacks(&data->callbacks, dev, evt);
}
static int espi_promt0_setup(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct rts5912_sccon_subsys sccon;
volatile struct acpi_reg *const promt0_reg = espi_config->promt0_reg;
int rc;
if (!device_is_ready(espi_config->clk_dev)) {
LOG_ERR("Promt0 clock not ready");
return -ENODEV;
}
sccon.clk_grp = espi_config->promt0_clk_grp;
sccon.clk_idx = espi_config->promt0_clk_idx;
rc = clock_control_on(espi_config->clk_dev, (clock_control_subsys_t)&sccon);
if (rc != 0) {
LOG_ERR("Promt0 clock control on failed");
return rc;
}
promt0_reg->STS = 0;
if (promt0_reg->STS & ACPI_STS_IBF) {
rc = promt0_reg->IB;
}
if (promt0_reg->STS & ACPI_STS_IBF) {
promt0_reg->IB |= ACPI_IB_IBCLR;
}
promt0_reg->PTADDR =
CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM | (0x04 << ACPI_PTADDR_OFFSET_Pos);
promt0_reg->VWCTRL1 = ACPI_VWCTRL1_ACTEN;
promt0_reg->INTEN = ACPI_INTEN_IBFINTEN;
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), promt0_ibf, irq));
/* IBF */
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), promt0_ibf, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), promt0_ibf, priority), promt0_ibf_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), promt0_ibf, irq));
return 0;
}
#endif /* CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD */
/*
* =========================================================================
* ESPI Peripheral Channel Read/Write API
* =========================================================================
*/
#ifdef CONFIG_ESPI_PERIPHERAL_CHANNEL
static void espi_periph_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_PERIPHERAL,
.evt_data = 0};
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint32_t status = espi_reg->EPSTS;
uint32_t config = espi_reg->EPCFG;
if (status & ESPI_EPSTS_CLRSTS) {
evt.evt_data = config & ESPI_EPCFG_CHEN ? 1 : 0;
espi_send_callbacks(&data->callbacks, dev, evt);
espi_reg->EPSTS = ESPI_EPSTS_CLRSTS;
}
}
static int lpc_request_read_custom(const struct espi_rts5912_config *const espi_config,
enum lpc_peripheral_opcode op, uint32_t *data)
{
#ifdef CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE
switch (op) {
case ECUSTOM_HOST_CMD_GET_PARAM_MEMORY:
*data = (uint32_t)ec_host_cmd_sram;
break;
case ECUSTOM_HOST_CMD_GET_PARAM_MEMORY_SIZE:
*data = ESPI_RTK_PERIPHERAL_HOST_CMD_PARAM_SIZE;
break;
default:
return -EINVAL;
}
return 0;
#else
return -ENOTSUP;
#endif
}
static int espi_rts5912_read_lpc_request(const struct device *dev, enum lpc_peripheral_opcode op,
uint32_t *data)
{
const struct espi_rts5912_config *const espi_config = dev->config;
if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) {
return lpc_request_read_8042(dev, op, data);
} else if (op >= EACPI_START_OPCODE && op <= EACPI_MAX_OPCODE) {
return lpc_request_read_acpi(espi_config, op, data);
} else if (op >= ECUSTOM_START_OPCODE && op <= ECUSTOM_MAX_OPCODE) {
return lpc_request_read_custom(espi_config, op, data);
} else {
return -ENOTSUP;
}
}
static int lpc_request_write_custom(const struct espi_rts5912_config *const espi_config,
enum lpc_peripheral_opcode op, uint32_t *data)
{
#ifdef CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE
volatile struct acpi_reg *const promt0_reg = espi_config->promt0_reg;
switch (op) {
case ECUSTOM_HOST_SUBS_INTERRUPT_EN:
if (*data == 0) {
NVIC_DisableIRQ((DT_IRQ_BY_NAME(DT_DRV_INST(0), promt0_ibf, irq)));
NVIC_DisableIRQ((DT_IRQ_BY_NAME(DT_DRV_INST(0), acpi_ibf, irq)));
NVIC_DisableIRQ((DT_IRQ_BY_NAME(DT_DRV_INST(0), port80, irq)));
NVIC_DisableIRQ((DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_ibf, irq)));
NVIC_DisableIRQ((DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_obe, irq)));
} else {
NVIC_EnableIRQ((DT_IRQ_BY_NAME(DT_DRV_INST(0), promt0_ibf, irq)));
NVIC_EnableIRQ((DT_IRQ_BY_NAME(DT_DRV_INST(0), acpi_ibf, irq)));
NVIC_EnableIRQ((DT_IRQ_BY_NAME(DT_DRV_INST(0), port80, irq)));
NVIC_EnableIRQ((DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_ibf, irq)));
NVIC_EnableIRQ((DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_obe, irq)));
}
break;
case ECUSTOM_HOST_CMD_SEND_RESULT:
promt0_reg->STS &= ~ACPI_STS_STS0;
promt0_reg->OB = *data & 0xff;
break;
default:
return -EINVAL;
}
return 0;
#else
return -ENOTSUP;
#endif
}
static int espi_rts5912_write_lpc_request(const struct device *dev, enum lpc_peripheral_opcode op,
uint32_t *data)
{
const struct espi_rts5912_config *const espi_config = dev->config;
if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) {
return lpc_request_write_8042(dev, op, data);
} else if (op >= EACPI_START_OPCODE && op <= EACPI_MAX_OPCODE) {
return lpc_request_write_acpi(espi_config, op, data);
} else if (op >= ECUSTOM_START_OPCODE && op <= ECUSTOM_MAX_OPCODE) {
return lpc_request_write_custom(espi_config, op, data);
} else {
return -ENOTSUP;
}
}
static void espi_periph_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->EPINTEN = ESPI_EPINTEN_CFGCHGEN | ESPI_EPINTEN_MEMWREN | ESPI_EPINTEN_MEMRDEN;
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), periph_ch, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), periph_ch, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), periph_ch, priority), espi_periph_ch_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), periph_ch, irq));
}
#endif /* CONFIG_ESPI_PERIPHERAL_CHANNEL */
/*
* =========================================================================
* ESPI Peripheral Debug Port 80
* =========================================================================
*/
#ifdef CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80
static void espi_port80_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
struct espi_event evt = {ESPI_BUS_PERIPHERAL_NOTIFICATION,
ESPI_PERIPHERAL_INDEX_0 << 16 | ESPI_PERIPHERAL_DEBUG_PORT80,
ESPI_PERIPHERAL_NODATA};
volatile struct port80_reg *const port80_reg = espi_config->port80_reg;
evt.evt_data = port80_reg->DATA;
espi_send_callbacks(&espi_data->callbacks, dev, evt);
}
static int espi_peri_ch_port80_setup(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct rts5912_sccon_subsys sccon;
volatile struct port80_reg *const port80_reg = espi_config->port80_reg;
int rc;
if (!device_is_ready(espi_config->clk_dev)) {
return -ENODEV;
}
sccon.clk_grp = espi_config->port80_clk_grp;
sccon.clk_idx = espi_config->port80_clk_idx;
rc = clock_control_on(espi_config->clk_dev, (clock_control_subsys_t)&sccon);
if (rc != 0) {
return rc;
}
port80_reg->ADDR = 0x80UL;
port80_reg->CFG = PORT80_CFG_CLRFLG | PORT80_CFG_THREEN;
port80_reg->INTEN = PORT80_INTEN_THREINTEN;
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), port80, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), port80, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), port80, priority), espi_port80_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), port80, irq));
return 0;
}
#endif /* CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80 */
/*
* =========================================================================
* 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));
}
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
#define ESPI_VW_EVENT_IDLE_TIMEOUT_US 1024UL
#define ESPI_VW_EVENT_COMPLETE_TIMEOUT_US 10000UL
static int espi_send_vw_event(uint8_t index, uint8_t data, const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
uint32_t i;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
if ((espi_reg->EVCFG & ESPI_EVCFG_CHEN) == 0 || (espi_reg->EVCFG & ESPI_EVCFG_CHRDY) == 0) {
return -EBUSY;
}
/* Wait for TX FIFO to not be full before writing, with timeout */
if (!WAIT_FOR(!(espi_reg->EVSTS & ESPI_EVSTS_TXFULL), ESPI_VW_EVENT_IDLE_TIMEOUT_US,
k_busy_wait(1))) {
return -EBUSY;
}
i = 0x0000FFFF & ((uint32_t)index << 8 | (uint32_t)data);
espi_reg->EVTXDAT = i;
/* Wait for TX FIFO to not be full after writing, with shorter timeout */
if (!WAIT_FOR(!(espi_reg->EVSTS & ESPI_EVSTS_TXFULL), ESPI_VW_EVENT_COMPLETE_TIMEOUT_US,
NULL)) {
return -EBUSY;
}
espi_reg->EVSTS |= ESPI_EVSTS_TXDONE;
return 0;
}
static void espi_send_vw_event_with_kbdata(uint8_t index, uint8_t data, uint32_t kbc_data,
const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *const espi_data = dev->data;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
volatile struct kbc_reg *const kbc_reg = espi_config->kbc_reg;
uint32_t i;
if ((espi_reg->EVCFG & ESPI_EVCFG_CHEN) == 0 || (espi_reg->EVCFG & ESPI_EVCFG_CHRDY) == 0) {
return;
}
/* Wait for TX FIFO to not be full before writing, with timeout */
if (!WAIT_FOR(!(espi_reg->EVSTS & ESPI_EVSTS_TXFULL), ESPI_VW_EVENT_COMPLETE_TIMEOUT_US,
k_busy_wait(1))) {
return;
}
__disable_irq();
kbc_reg->OB = kbc_data;
i = 0x0000FFFF & ((uint32_t)index << 8 | (uint32_t)data);
espi_reg->EVTXDAT = i;
/* Wait for TX FIFO to not be full after writing, in IRQ disabled state */
if (!WAIT_FOR(!(espi_reg->EVSTS & ESPI_EVSTS_TXFULL), ESPI_VW_EVENT_COMPLETE_TIMEOUT_US,
k_busy_wait(1))) {
espi_data->kbc_pre_irq1 = 1;
__enable_irq();
return;
}
espi_data->kbc_pre_irq1 = 1;
espi_reg->EVSTS |= ESPI_EVSTS_TXDONE;
__enable_irq();
}
#endif /* CONFIG_ESPI_PERIPHERAL_8042_KBC */
#endif /* CONFIG_ESPI_VWIRE_CHANNEL */
/*
* =========================================================================
* ESPI OOB channel
* =========================================================================
*/
#ifdef CONFIG_ESPI_OOB_CHANNEL
#define MAX_OOB_TIMEOUT 200UL /* ms */
#define OOB_BUFFER_SIZE 256UL
static int espi_rts5912_send_oob(const struct device *dev, struct espi_oob_packet *pckt)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
int ret;
if (!(espi_reg->EOCFG & ESPI_EOCFG_CHRDY)) {
LOG_ERR("%s: OOB channel isn't ready", __func__);
return -EIO;
}
if (espi_data->oob_tx_busy) {
LOG_ERR("%s: OOB channel is busy", __func__);
return -EIO;
}
if (pckt->len > OOB_BUFFER_SIZE) {
LOG_ERR("%s: OOB Tx have no insufficient space", __func__);
return -EINVAL;
}
for (int i = 0; i < pckt->len; i++) {
espi_data->oob_tx_ptr[i] = pckt->buf[i];
}
espi_reg->EOTXLEN = pckt->len - 1;
espi_reg->EOTXCTRL = ESPI_EOTXCTRL_TXSTR;
espi_data->oob_tx_busy = true;
/* Wait until ISR or timeout */
ret = k_sem_take(&espi_data->oob_tx_lock, K_MSEC(MAX_OOB_TIMEOUT));
if (ret == -EAGAIN) {
return -ETIMEDOUT;
}
espi_data->oob_tx_busy = false;
return 0;
}
static int espi_rts5912_receive_oob(const struct device *dev, struct espi_oob_packet *pckt)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint32_t rx_len;
if (!(espi_reg->EOCFG & ESPI_EOCFG_CHRDY)) {
LOG_ERR("%s: OOB channel isn't ready", __func__);
return -EIO;
}
if (espi_reg->EOSTS & ESPI_EOSTS_RXPND) {
LOG_ERR("OOB Receive Pending");
return -EIO;
}
#ifndef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
/* Wait until ISR or timeout */
int ret = k_sem_take(&espi_data->oob_rx_lock, K_MSEC(MAX_OOB_TIMEOUT));
if (ret == -EAGAIN) {
LOG_ERR("OOB Rx Timeout");
return -ETIMEDOUT;
}
#endif
/* Check if buffer passed to driver can fit the received buffer */
rx_len = espi_reg->EORXLEN;
if (rx_len > pckt->len) {
LOG_ERR("space rcvd %d vs %d", rx_len, pckt->len);
return -EIO;
}
pckt->len = rx_len;
for (int i = 0; i < rx_len; i++) {
pckt->buf[i] = espi_data->oob_rx_ptr[i];
}
return 0;
}
static void espi_oob_tx_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint32_t status = espi_reg->EOSTS;
if (status & ESPI_EOSTS_TXDONE) {
k_sem_give(&espi_data->oob_tx_lock);
espi_reg->EOSTS = ESPI_EOSTS_TXDONE;
}
}
static void espi_oob_rx_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint32_t status = espi_reg->EOSTS;
#ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
struct espi_event evt = {
.evt_type = ESPI_BUS_EVENT_OOB_RECEIVED, .evt_details = 0, .evt_data = 0};
#endif
if (status & ESPI_EOSTS_RXDONE) {
#ifndef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
k_sem_give(&espi_data->oob_rx_lock);
#else
k_busy_wait(250);
evt.evt_details = espi_reg->EORXLEN;
espi_send_callbacks(&espi_data->callbacks, dev, evt);
#endif
espi_reg->EOSTS = ESPI_EOSTS_RXDONE;
}
}
static void espi_oob_chg_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
struct espi_event evt = {.evt_type = ESPI_BUS_EVENT_CHANNEL_READY,
.evt_details = ESPI_CHANNEL_OOB,
.evt_data = 0};
uint32_t status = espi_reg->EOSTS;
uint32_t config = espi_reg->EOCFG;
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;
}
}
static uint8_t oob_tx_buffer[OOB_BUFFER_SIZE] __aligned(4);
static uint8_t oob_rx_buffer[OOB_BUFFER_SIZE] __aligned(4);
static int espi_oob_ch_setup(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
espi_data->oob_tx_busy = false;
espi_data->oob_tx_ptr = oob_tx_buffer;
if (espi_data->oob_tx_ptr == NULL) {
LOG_ERR("Failed to allocate OOB Tx buffer");
return -ENOMEM;
}
espi_data->oob_rx_ptr = oob_rx_buffer;
if (espi_data->oob_tx_ptr == NULL) {
LOG_ERR("Failed to allocate OOB Rx buffer");
return -ENOMEM;
}
espi_reg->EOTXBUF = (uint32_t)espi_data->oob_tx_ptr;
espi_reg->EORXBUF = (uint32_t)espi_data->oob_rx_ptr;
espi_reg->EOTXINTEN = ESPI_EOTXINTEN_TXEN;
espi_reg->EORXINTEN = (ESPI_EORXINTEN_RXEN | ESPI_EORXINTEN_CHENCHG);
k_sem_init(&espi_data->oob_tx_lock, 0, 1);
#ifndef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
k_sem_init(&espi_data->oob_rx_lock, 0, 1);
#endif
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), oob_tx, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), oob_rx, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), oob_chg, irq));
/* Tx */
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), oob_tx, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), oob_tx, priority), espi_oob_tx_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), oob_tx, irq));
/* Rx */
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), oob_rx, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), oob_rx, priority), espi_oob_rx_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), oob_rx, irq));
/* Chg */
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), oob_chg, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), oob_chg, priority), espi_oob_chg_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), oob_chg, irq));
return 0;
}
#endif /* CONFIG_ESPI_OOB_CHANNEL */
/*
* =========================================================================
* ESPI flash channel
* =========================================================================
*/
#ifdef CONFIG_ESPI_FLASH_CHANNEL
#define MAX_FLASH_TIMEOUT 1000UL
#define MAF_BUFFER_SIZE 512UL
enum {
MAF_TR_READ = 0,
MAF_TR_WRITE = 1,
MAF_TR_ERASE = 2,
};
static int espi_rts5912_flash_read(const struct device *dev, struct espi_flash_packet *pckt)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
int ret;
uint32_t ctrl;
if (!(espi_reg->EFCONF & ESPI_EFCONF_CHEN)) {
LOG_ERR("Flash channel is disabled");
return -EIO;
}
if (pckt->len > MAF_BUFFER_SIZE) {
LOG_ERR("Invalid size request");
return -EINVAL;
}
if (espi_reg->EMCTRL & ESPI_EMCTRL_START) {
LOG_ERR("Channel still busy");
return -EBUSY;
}
ctrl = (MAF_TR_READ << ESPI_EMCTRL_MDSEL_Pos) | ESPI_EMCTRL_START;
espi_reg->EMADR = pckt->flash_addr;
espi_reg->EMTRLEN = pckt->len;
espi_reg->EMCTRL = ctrl;
/* Wait until ISR or timeout */
ret = k_sem_take(&espi_data->flash_lock, K_MSEC(MAX_FLASH_TIMEOUT));
if (ret == -EAGAIN) {
LOG_ERR("%s timeout", __func__);
return -ETIMEDOUT;
}
for (int i = 0; i < pckt->len; i++) {
pckt->buf[i] = espi_data->maf_ptr[i];
}
return 0;
}
static int espi_rts5912_flash_write(const struct device *dev, struct espi_flash_packet *pckt)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
int ret;
uint32_t ctrl;
if (!(espi_reg->EFCONF & ESPI_EFCONF_CHEN)) {
LOG_ERR("Flash channel is disabled");
return -EIO;
}
if (pckt->len > MAF_BUFFER_SIZE) {
LOG_ERR("Packet length is too big");
return -EINVAL;
}
if (espi_reg->EMCTRL & ESPI_EMCTRL_START) {
LOG_ERR("Channel still busy");
return -EBUSY;
}
for (int i = 0; i < pckt->len; i++) {
espi_data->maf_ptr[i] = pckt->buf[i];
}
ctrl = (MAF_TR_WRITE << ESPI_EMCTRL_MDSEL_Pos) | ESPI_EMCTRL_START;
espi_reg->EMADR = pckt->flash_addr;
espi_reg->EMTRLEN = pckt->len;
espi_reg->EMCTRL = ctrl;
/* Wait until ISR or timeout */
ret = k_sem_take(&espi_data->flash_lock, K_MSEC(MAX_FLASH_TIMEOUT));
if (ret == -EAGAIN) {
LOG_ERR("%s timeout", __func__);
return -ETIMEDOUT;
}
return 0;
}
static int espi_rts5912_flash_erase(const struct device *dev, struct espi_flash_packet *pckt)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
int ret;
uint32_t ctrl;
if (!(espi_reg->EFCONF & ESPI_EFCONF_CHEN)) {
LOG_ERR("Flash channel is disabled");
return -EIO;
}
if (espi_reg->EMCTRL & ESPI_EMCTRL_START) {
LOG_ERR("Channel still busy");
return -EBUSY;
}
ctrl = (MAF_TR_ERASE << ESPI_EMCTRL_MDSEL_Pos) | ESPI_EMCTRL_START;
espi_reg->EMADR = pckt->flash_addr;
espi_reg->EMTRLEN = pckt->len;
espi_reg->EMCTRL = ctrl;
/* Wait until ISR or timeout */
ret = k_sem_take(&espi_data->flash_lock, K_MSEC(MAX_FLASH_TIMEOUT));
if (ret == -EAGAIN) {
LOG_ERR("%s timeout", __func__);
return -ETIMEDOUT;
}
return 0;
}
static void espi_maf_tr_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint32_t status = espi_reg->EFSTS;
if (status & ESPI_EFSTS_MAFTXDN) {
k_sem_give(&espi_data->flash_lock);
espi_reg->EFSTS = ESPI_EFSTS_MAFTXDN;
}
}
static void espi_flash_chg_isr(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
struct espi_event evt = {.evt_type = ESPI_BUS_EVENT_CHANNEL_READY,
.evt_details = ESPI_CHANNEL_FLASH,
.evt_data = 0};
uint32_t status = espi_reg->EFSTS;
uint32_t config = espi_reg->EFCONF;
if (status & ESPI_EFSTS_CHENCHG) {
evt.evt_data = (config & ESPI_EFCONF_CHEN) ? 1 : 0;
espi_send_callbacks(&espi_data->callbacks, dev, evt);
espi_reg->EFSTS = ESPI_EFSTS_CHENCHG;
}
}
static uint8_t flash_channel_buffer[MAF_BUFFER_SIZE] __aligned(4);
static int espi_flash_ch_setup(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *espi_data = dev->data;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
espi_data->maf_ptr = flash_channel_buffer;
if (espi_data->maf_ptr == NULL) {
LOG_ERR("Failed to allocate MAF buffer");
return -ENOMEM;
}
espi_reg->EMBUF = (uint32_t)espi_data->maf_ptr;
espi_reg->EMINTEN = ESPI_EMINTEN_CHENCHG | ESPI_EMINTEN_TRDONEEN;
k_sem_init(&espi_data->flash_lock, 0, 1);
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), maf_tr, irq));
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), flash_chg, irq));
/* MAF Tr */
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), maf_tr, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), maf_tr, priority), espi_maf_tr_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), maf_tr, irq));
/* Chg */
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), flash_chg, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), flash_chg, priority), espi_flash_chg_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), flash_chg, irq));
return 0;
}
#endif /* CONFIG_ESPI_FLASH_CHANNEL */
/*
* =========================================================================
* ESPI common function and API
* =========================================================================
*/
#define RTS5912_ESPI_MAX_FREQ_20 20
#define RTS5912_ESPI_MAX_FREQ_25 25
#define RTS5912_ESPI_MAX_FREQ_33 33
#define RTS5912_ESPI_MAX_FREQ_50 50
#define RTS5912_ESPI_MAX_FREQ_66 66
static int espi_rts5912_configure(const struct device *dev, struct espi_cfg *cfg)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct espi_rts5912_data *data = dev->data;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint32_t gen_conf = 0;
uint8_t io_mode = 0;
/* Maximum Frequency Supported */
switch (cfg->max_freq) {
case RTS5912_ESPI_MAX_FREQ_20:
gen_conf |= 0UL << ESPI_ESPICFG_MXFREQSUP_Pos;
break;
case RTS5912_ESPI_MAX_FREQ_25:
gen_conf |= 1UL << ESPI_ESPICFG_MXFREQSUP_Pos;
break;
case RTS5912_ESPI_MAX_FREQ_33:
gen_conf |= 2UL << ESPI_ESPICFG_MXFREQSUP_Pos;
break;
case RTS5912_ESPI_MAX_FREQ_50:
gen_conf |= 3UL << ESPI_ESPICFG_MXFREQSUP_Pos;
break;
case RTS5912_ESPI_MAX_FREQ_66:
gen_conf |= 4UL << ESPI_ESPICFG_MXFREQSUP_Pos;
break;
default:
return -EINVAL;
}
/* I/O Mode Supported */
io_mode = cfg->io_caps >> 1;
if (io_mode > 3) {
return -EINVAL;
}
gen_conf |= io_mode << ESPI_ESPICFG_IOSUP_Pos;
/* Channel Supported */
if (cfg->channel_caps & ESPI_CHANNEL_PERIPHERAL) {
gen_conf |= BIT(0) << ESPI_ESPICFG_CHSUP_Pos;
}
if (cfg->channel_caps & ESPI_CHANNEL_VWIRE) {
gen_conf |= BIT(1) << ESPI_ESPICFG_CHSUP_Pos;
}
if (cfg->channel_caps & ESPI_CHANNEL_OOB) {
gen_conf |= BIT(2) << ESPI_ESPICFG_CHSUP_Pos;
}
if (cfg->channel_caps & ESPI_CHANNEL_FLASH) {
gen_conf |= BIT(3) << ESPI_ESPICFG_CHSUP_Pos;
}
espi_reg->ESPICFG = gen_conf;
data->config_data = espi_reg->ESPICFG;
return 0;
}
static bool espi_rts5912_channel_ready(const struct device *dev, enum espi_channel ch)
{
const struct espi_rts5912_config *const espi_config = dev->config;
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
switch (ch) {
case ESPI_CHANNEL_PERIPHERAL:
return espi_reg->EPCFG & ESPI_EPCFG_CHEN ? true : false;
case ESPI_CHANNEL_VWIRE:
return espi_reg->EVCFG & ESPI_EVCFG_CHEN ? true : false;
case ESPI_CHANNEL_OOB:
return espi_reg->EOCFG & ESPI_EOCFG_CHEN ? true : false;
case ESPI_CHANNEL_FLASH:
return espi_reg->EFCONF & ESPI_EFCONF_CHEN ? true : false;
default:
return false;
}
}
static int espi_rts5912_manage_callback(const struct device *dev, struct espi_callback *callback,
bool set)
{
struct espi_rts5912_data *data = dev->data;
return espi_manage_callback(&data->callbacks, callback, set);
}
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_PERIPHERAL_CHANNEL
.read_lpc_request = espi_rts5912_read_lpc_request,
.write_lpc_request = espi_rts5912_write_lpc_request,
#endif
#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,
#endif
#ifdef CONFIG_ESPI_FLASH_CHANNEL
.flash_read = espi_rts5912_flash_read,
.flash_write = espi_rts5912_flash_write,
.flash_erase = espi_rts5912_flash_erase,
#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;
struct espi_rts5912_data *data = dev->data;
struct espi_event evt = {.evt_type = ESPI_BUS_RESET, .evt_details = 0, .evt_data = 0};
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
uint32_t status = espi_reg->ERSTCFG;
espi_reg->ERSTCFG |= ESPI_ERSTCFG_RSTSTS;
espi_reg->ERSTCFG ^= ESPI_ERSTCFG_RSTPOL;
if (status & ESPI_ERSTCFG_RSTSTS) {
if (status & ESPI_ERSTCFG_RSTPOL) {
/* rst pin high go low trigger interrupt */
evt.evt_data = 0;
} 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);
}
}
static void espi_bus_reset_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->ERSTCFG = ESPI_ERSTCFG_RSTINTEN;
espi_reg->ERSTCFG = ESPI_ERSTCFG_RSTMONEN;
if (espi_reg->ERSTCFG & ESPI_ERSTCFG_RSTSTS) {
/* high to low */
espi_reg->ERSTCFG =
ESPI_ERSTCFG_RSTMONEN | ESPI_ERSTCFG_RSTPOL | ESPI_ERSTCFG_RSTINTEN;
} else {
/* low to high */
espi_reg->ERSTCFG = ESPI_ERSTCFG_RSTMONEN | ESPI_ERSTCFG_RSTINTEN;
}
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), bus_rst, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), bus_rst, irq),
DT_IRQ_BY_NAME(DT_DRV_INST(0), bus_rst, priority), espi_rst_isr,
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), bus_rst, irq));
}
static int espi_rts5912_init(const struct device *dev)
{
const struct espi_rts5912_config *const espi_config = dev->config;
struct rts5912_sccon_subsys sccon;
int rc;
/* Setup eSPI pins */
rc = pinctrl_apply_state(espi_config->pcfg, PINCTRL_STATE_DEFAULT);
if (rc < 0) {
LOG_ERR("eSPI pinctrl setup failed (%d)", rc);
return rc;
}
if (!device_is_ready(espi_config->clk_dev)) {
LOG_ERR("eSPI clock not ready");
return -ENODEV;
}
/* Enable eSPI clock */
sccon.clk_grp = espi_config->espislv_clk_grp;
sccon.clk_idx = espi_config->espislv_clk_idx;
rc = clock_control_on(espi_config->clk_dev, (clock_control_subsys_t)&sccon);
if (rc != 0) {
LOG_ERR("eSPI clock control on failed");
goto exit;
}
/* Setup eSPI bus reset */
espi_bus_reset_setup(dev);
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
/* Setup KBC */
rc = espi_kbc_setup(dev);
if (rc != 0) {
LOG_ERR("eSPI KBC setup failed");
goto exit;
}
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION
espi_setup_acpi_shm(espi_config);
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO
/* Setup ACPI */
rc = espi_acpi_setup(dev);
if (rc != 0) {
LOG_ERR("eSPI ACPI setup failed");
goto exit;
}
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD
rc = espi_promt0_setup(dev);
if (rc != 0) {
LOG_ERR("eSPI Promt0 setup failed");
goto exit;
}
espi_setup_host_cmd_shm(espi_config);
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80
/* Setup Port80 */
rc = espi_peri_ch_port80_setup(dev);
if (rc != 0) {
LOG_ERR("eSPI Port80 setup failed");
goto exit;
}
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_CHANNEL
/* Setup eSPI peripheral channel */
espi_periph_ch_setup(dev);
#endif
#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);
if (rc != 0) {
LOG_ERR("eSPI OOB channel setup failed");
goto exit;
}
#endif
#ifdef CONFIG_ESPI_FLASH_CHANNEL
/* Setup eSPI flash channel */
rc = espi_flash_ch_setup(dev);
if (rc != 0) {
LOG_ERR("eSPI flash channel setup failed");
goto exit;
}
#endif
exit:
return rc;
}
PINCTRL_DT_INST_DEFINE(0);
static struct espi_rts5912_data espi_rts5912_data_0;
static const struct espi_rts5912_config espi_rts5912_config = {
.espi_reg = (volatile struct espi_reg *const)DT_INST_REG_ADDR_BY_NAME(0, espi_target),
.espislv_clk_grp = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), espi_target, clk_grp),
.espislv_clk_idx = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), espi_target, clk_idx),
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
.kbc_reg = (volatile struct kbc_reg *const)DT_INST_REG_ADDR_BY_NAME(0, kbc),
.kbc_clk_grp = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), kbc, clk_grp),
.kbc_clk_idx = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), kbc, clk_idx),
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO
.acpi_reg = (volatile struct acpi_reg *const)DT_INST_REG_ADDR_BY_NAME(0, acpi),
.acpi_clk_grp = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), acpi, clk_grp),
.acpi_clk_idx = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), acpi, clk_idx),
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD
.promt0_reg = (volatile struct acpi_reg *const)DT_INST_REG_ADDR_BY_NAME(0, promt0),
.promt0_clk_grp = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), promt0, clk_grp),
.promt0_clk_idx = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), promt0, clk_idx),
.emi0_reg = (volatile struct emi_reg *const)DT_INST_REG_ADDR_BY_NAME(0, emi0),
.emi0_clk_grp = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), emi0, clk_grp),
.emi0_clk_idx = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), emi0, clk_idx),
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION
.emi1_reg = (volatile struct emi_reg *const)DT_INST_REG_ADDR_BY_NAME(0, emi1),
.emi1_clk_grp = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), emi1, clk_grp),
.emi1_clk_idx = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), emi1, clk_idx),
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80
.port80_reg = (volatile struct port80_reg *const)DT_INST_REG_ADDR_BY_NAME(0, port80),
.port80_clk_grp = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), port80, clk_grp),
.port80_clk_idx = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), port80, clk_idx),
#endif
.clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0)),
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
};
DEVICE_DT_INST_DEFINE(0, &espi_rts5912_init, NULL, &espi_rts5912_data_0, &espi_rts5912_config,
PRE_KERNEL_2, CONFIG_ESPI_INIT_PRIORITY, &espi_rts5912_driver_api);