Microchip: MEC172x: eSPI driver

MEC172x eSPI driver, eSPI pin programming, interrupt updates related
to eSPI and other updates for MEC172x eSPI driver.

Signed-off-by: Jay Vasanth <jay.vasanth@microchip.com>
This commit is contained in:
Jay Vasanth 2021-10-18 16:44:45 -04:00 committed by Christopher Friedt
commit c214c59548
24 changed files with 3291 additions and 79 deletions

View file

@ -8,3 +8,5 @@ zephyr_library_sources_ifdef(CONFIG_ESPI_NPCX host_subs_npcx.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE espi_handlers.c)
zephyr_library_sources_ifdef(CONFIG_ESPI_EMUL espi_emul.c)
zephyr_library_sources_ifdef(CONFIG_ESPI_SAF espi_saf_mchp_xec.c)
zephyr_library_sources_ifdef(CONFIG_ESPI_XEC_V2 espi_mchp_xec_v2.c)
zephyr_library_sources_ifdef(CONFIG_ESPI_XEC_V2 espi_mchp_xec_host_v2.c)

View file

@ -12,6 +12,8 @@ if ESPI
source "drivers/espi/Kconfig.xec"
source "drivers/espi/Kconfig.xec_v2"
source "drivers/espi/Kconfig.npcx"
source "drivers/espi/Kconfig.espi_emul"

View file

@ -5,9 +5,9 @@
config ESPI_XEC
bool "XEC Microchip ESPI driver"
depends on SOC_FAMILY_MEC
depends on SOC_SERIES_MEC1501X
help
Enable the Microchip XEC ESPI driver.
Enable the Microchip XEC ESPI driver for MEC15xx family.
if ESPI_XEC

132
drivers/espi/Kconfig.xec_v2 Normal file
View file

@ -0,0 +1,132 @@
# Microchip XEC ESPI configuration options
# Copyright (c) 2019 Intel Corporation
# Copyright (c) 2021 Microchip Technology Inc.
# SPDX-License-Identifier: Apache-2.0
config ESPI_XEC_V2
bool "XEC Microchip ESPI V2 driver"
depends on SOC_SERIES_MEC172X
help
Enable the Microchip XEC ESPI driver for MEC172x series.
if ESPI_XEC_V2
config ESPI_OOB_CHANNEL
default y
config ESPI_FLASH_CHANNEL
default y
config ESPI_PERIPHERAL_HOST_IO
default y
config ESPI_PERIPHERAL_HOST_IO_PVT
default y
config ESPI_PERIPHERAL_DEBUG_PORT_80
default y
config ESPI_PERIPHERAL_8042_KBC
default y
config ESPI_PERIPHERAL_UART
default y
config ESPI_PERIPHERAL_UART_SOC_MAPPING
int "SoC port exposed as logical eSPI UART"
default 1
depends on ESPI_PERIPHERAL_UART
help
This tells the driver to which SoC UART to direct the UART traffic
send over eSPI from host. MEC172x implements two UARTs.
config ESPI_PERIPHERAL_XEC_MAILBOX
bool "SoC Mailbox over eSPI"
depends on ESPI_PERIPHERAL_CHANNEL
help
Enable a 32 byte mailbox interface accessible via Host I/O over the
ESPI Peripheral Channel.
config ESPI_PERIPHERAL_XEC_ACPI_EC2
bool "SoC ACPI EC 2 over eSPI"
depends on ESPI_PERIPHERAL_CHANNEL
help
Enable ACPI EC2 interface accessible via Host I/O over the
ESPI Peripheral Channel.
config ESPI_PERIPHERAL_XEC_ACPI_EC3
bool "SoC ACPI EC 3 over eSPI"
depends on ESPI_PERIPHERAL_CHANNEL
help
Enable ACPI EC3 interface accessible via Host I/O over the
ESPI Peripheral Channel.
config ESPI_PERIPHERAL_XEC_ACPI_EC4
bool "SoC ACPI EC 4 over eSPI"
depends on ESPI_PERIPHERAL_CHANNEL
help
Enable ACPI EC4 interface accessible via Host I/O over the
ESPI Peripheral Channel.
config ESPI_PERIPHERAL_XEC_ACPI_PM1
bool "SoC ACPI PM1 over eSPI"
depends on ESPI_PERIPHERAL_CHANNEL
help
Enable ACPI PM1 interface accessible via Host I/O over the
ESPI Peripheral Channel.
config ESPI_PERIPHERAL_XEC_EMI0
bool "SoC EMI 0 over eSPI"
depends on ESPI_PERIPHERAL_CHANNEL
help
Enable EMI 0 interface accessible via Host I/O over the
ESPI Peripheral Channel.
config ESPI_PERIPHERAL_XEC_EMI1
bool "SoC EMI 1 over eSPI"
depends on ESPI_PERIPHERAL_CHANNEL
help
Enable EMI 1 interface accessible via Host I/O over the
ESPI Peripheral Channel.
config ESPI_PERIPHERAL_XEC_EMI2
bool "SoC EMI 2 over eSPI"
depends on ESPI_PERIPHERAL_CHANNEL
help
Enable EMI 2 interface accessible via Host I/O over the
ESPI Peripheral Channel.
config ESPI_OOB_BUFFER_SIZE
int "eSPI OOB channel buffer size in bytes"
default 128
depends on ESPI_OOB_CHANNEL
help
Use minimum RAM buffer size by default but allow applications to
override the value.
Maximum OOB payload is 73 bytes.
config ESPI_FLASH_BUFFER_SIZE
int "eSPI Flash channel buffer size in bytes"
default 256
depends on ESPI_FLASH_CHANNEL
help
Use maximum RAM buffer size defined by spec but allow applications
to override if eSPI host doesn't support it.
config ESPI_SAF
bool "XEC Microchip ESPI SAF driver"
depends on ESPI_FLASH_CHANNEL
default n
help
Enable Slave Attached Flash eSPI driver. SAF depends upon ESPI XEC driver
and flash channel.
config ESPI_SAF_INIT_PRIORITY
int "ESPI SAF driver initialization priority"
depends on ESPI_SAF
default 4
help
Driver initialization priority for eSPI SAF driver.
endif #ESPI_XEC_V2

View file

@ -0,0 +1,819 @@
/*
* Copyright (c) 2019 Intel Corporation
* Copyright (c) 2021 Microchip Technology Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT microchip_xec_espi_host_dev
#include <kernel.h>
#include <soc.h>
#include <errno.h>
#include <drivers/espi.h>
#include <drivers/clock_control/mchp_xec_clock_control.h>
#include <drivers/interrupt_controller/intc_mchp_xec_ecia.h>
#include <dt-bindings/interrupt-controller/mchp-xec-ecia.h>
#include <logging/log.h>
#include <sys/sys_io.h>
#include <sys/util.h>
#include "espi_utils.h"
#include "espi_mchp_xec_v2.h"
#define CONNECT_IRQ_MBOX0 NULL
#define CONNECT_IRQ_KBC0 NULL
#define CONNECT_IRQ_ACPI_EC0 NULL
#define CONNECT_IRQ_ACPI_EC1 NULL
#define CONNECT_IRQ_ACPI_EC2 NULL
#define CONNECT_IRQ_ACPI_EC3 NULL
#define CONNECT_IRQ_ACPI_EC4 NULL
#define CONNECT_IRQ_ACPI_PM1 NULL
#define CONNECT_IRQ_EMI0 NULL
#define CONNECT_IRQ_EMI1 NULL
#define CONNECT_IRQ_EMI2 NULL
#define CONNECT_IRQ_RTC0 NULL
#define CONNECT_IRQ_P80BD0 NULL
#define INIT_MBOX0 NULL
#define INIT_KBC0 NULL
#define INIT_ACPI_EC0 NULL
#define INIT_ACPI_EC1 NULL
#define INIT_ACPI_EC2 NULL
#define INIT_ACPI_EC3 NULL
#define INIT_ACPI_EC4 NULL
#define INIT_ACPI_PM1 NULL
#define INIT_EMI0 NULL
#define INIT_EMI1 NULL
#define INIT_EMI2 NULL
#define INIT_RTC0 NULL
#define INIT_P80BD0 NULL
#define INIT_UART0 NULL
#define INIT_UART1 NULL
/* BARs as defined in LPC spec chapter 11 */
#define ESPI_XEC_KBC_BAR_ADDRESS 0x00600000
#define ESPI_XEC_UART0_BAR_ADDRESS 0x03F80000
#define ESPI_XEC_MBOX_BAR_ADDRESS 0x03600000
#define ESPI_XEC_PORT80_BAR_ADDRESS 0x00800000
#define ESPI_XEC_PORT81_BAR_ADDRESS 0x00810000
#define ESPI_XEC_ACPI_EC0_BAR_ADDRESS 0x00620000
/* Espi peripheral has 3 uart ports */
#define ESPI_PERIPHERAL_UART_PORT0 0
#define ESPI_PERIPHERAL_UART_PORT1 1
#define UART_DEFAULT_IRQ_POS 2u
#define UART_DEFAULT_IRQ BIT(UART_DEFAULT_IRQ_POS)
/* PCR */
#define XEC_PCR_REG_BASE \
((struct pcr_regs *)(DT_REG_ADDR(DT_NODELABEL(pcr))))
struct xec_espi_host_sram_config {
uint32_t host_sram1_base;
uint32_t host_sram2_base;
uint16_t ec_sram1_ofs;
uint16_t ec_sram2_ofs;
uint8_t sram1_acc_size;
uint8_t sram2_acc_size;
};
struct xec_espi_host_dev_config {
const struct device *parent;
uint32_t reg_base; /* logical device registers */
uint32_t host_mem_base; /* 32-bit host memory address */
uint16_t host_io_base; /* 16-bit host I/O address */
uint8_t ldn; /* Logical device number */
uint8_t num_ecia;
uint32_t *girqs;
};
struct xec_acpi_ec_config {
uintptr_t regbase;
uint32_t ibf_ecia_info;
uint32_t obe_ecia_info;
};
#ifdef CONFIG_ESPI_PERIPHERAL_XEC_MAILBOX
BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_NODELABEL(mbox0), okay),
"XEC mbox0 DT node is disabled!");
static struct xec_mbox_config {
uintptr_t regbase;
uint32_t ecia_info;
};
static const struct xec_mbox0_config xec_mbox0_cfg = {
.regbase = DT_REG_ADDR(DT_NODELABEL(mbox0)),
.ecia_info = DT_PROP_BY_IDX(DT_NODELABEL(mbox0), girqs, 0),
};
/* dev is a pointer to espi0 (parent) device */
static void mbox0_isr(const struct device *dev)
{
uint8_t girq = MCHP_XEC_ECIA_GIRQ(xec_mbox0_cfg.ecia_info);
uint8_t bitpos = MCHP_XEC_ECIA_GIRQ_POS(xec_mbox0_cfg.ecia_info);
/* clear GIRQ source, inline version */
mchp_soc_ecia_girq_src_clr(girq, bitpos);
}
static int connect_irq_mbox0(const struct device *dev)
{
/* clear GIRQ source */
mchp_xec_ecia_info_girq_src_clr(xec_mbox0_cfg.ecia_info);
IRQ_CONNECT(DT_IRQN(DT_NODELABLE(mbox0)),
DT_IRQ(DT_NODELABLE(mbox0), priority),
acpi_ec0_isr,
DEVICE_DT_GET(DT_NODELABEL(espi0)),
0);
irq_enable(DT_IRQN(DT_NODELABLE(mbox0)));
/* enable GIRQ source */
mchp_xec_ecia_info_girq_src_en(xec_mbox0_cfg.ecia_info);
return 0;
}
/* Called by eSPI Bus init, eSPI reset de-assertion, and eSPI Platform Reset
* de-assertion.
*/
static int init_mbox0(const struct device *dev)
{
struct espi_xec_config *const cfg = ESPI_XEC_CONFIG(dev);
struct espi_iom_regs *regs = (struct espi_iom_regs *)cfg->base_addr;
regs->IOHBAR[IOB_MBOX] = ESPI_XEC_MBOX_BAR_ADDRESS |
MCHP_ESPI_IO_BAR_HOST_VALID;
return 0;
}
#undef CONNECT_IRQ_MBOX0
#define CONNECT_IRQ_MBOX0 connect_irq_mbox0
#undef INIT_MBOX0
#define INIT_MBOX0 init_mbox0
#endif /* CONFIG_ESPI_PERIPHERAL_XEC_MAILBOX */
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
BUILD_ASSERT(DT_NODE_HAS_STATUS(DT_NODELABEL(kbc0), okay),
"XEC kbc0 DT node is disabled!");
struct xec_kbc0_config {
uintptr_t regbase;
uint32_t ibf_ecia_info;
uint32_t obe_ecia_info;
};
static const struct xec_kbc0_config xec_kbc0_cfg = {
.regbase = DT_REG_ADDR(DT_NODELABEL(kbc0)),
.ibf_ecia_info = DT_PROP_BY_IDX(DT_NODELABEL(kbc0), girqs, 1),
.obe_ecia_info = DT_PROP_BY_IDX(DT_NODELABEL(kbc0), girqs, 0),
};
static void kbc0_ibf_isr(const struct device *dev)
{
struct kbc_regs *kbc_hw = (struct kbc_regs *)xec_kbc0_cfg.regbase;
struct espi_xec_data *const data =
(struct espi_xec_data *const)dev->data;
/* The high byte contains information from the host,
* and the lower byte speficies if the host sent
* a command or data. 1 = Command.
*/
uint32_t isr_data = ((kbc_hw->EC_DATA & 0xFF) << E8042_ISR_DATA_POS) |
((kbc_hw->EC_KBC_STS & MCHP_KBC_STS_CD) <<
E8042_ISR_CMD_DATA_POS);
struct espi_event evt = {
.evt_type = ESPI_BUS_PERIPHERAL_NOTIFICATION,
.evt_details = ESPI_PERIPHERAL_8042_KBC,
.evt_data = isr_data
};
espi_send_callbacks(&data->callbacks, dev, evt);
mchp_xec_ecia_info_girq_src_clr(xec_kbc0_cfg.ibf_ecia_info);
}
static void kbc0_obe_isr(const struct device *dev)
{
/* disable and clear GIRQ interrupt and status */
mchp_xec_ecia_info_girq_src_dis(xec_kbc0_cfg.obe_ecia_info);
mchp_xec_ecia_info_girq_src_clr(xec_kbc0_cfg.obe_ecia_info);
}
/* dev is a pointer to espi0 device */
static int kbc0_rd_req(const struct device *dev, enum lpc_peripheral_opcode op,
uint32_t *data)
{
struct kbc_regs *kbc_hw = (struct kbc_regs *)xec_kbc0_cfg.regbase;
ARG_UNUSED(dev);
if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) {
/* Make sure kbc 8042 is on */
if (!(kbc_hw->KBC_CTRL & MCHP_KBC_CTRL_OBFEN)) {
return -ENOTSUP;
}
switch (op) {
case E8042_OBF_HAS_CHAR:
/* EC has written data back to host. OBF is
* automatically cleared after host reads
* the data
*/
*data = kbc_hw->EC_KBC_STS & MCHP_KBC_STS_OBF ? 1 : 0;
break;
case E8042_IBF_HAS_CHAR:
*data = kbc_hw->EC_KBC_STS & MCHP_KBC_STS_IBF ? 1 : 0;
break;
case E8042_READ_KB_STS:
*data = kbc_hw->EC_KBC_STS;
break;
default:
return -EINVAL;
}
} else {
return -ENOTSUP;
}
return 0;
}
/* dev is a pointer to espi0 device */
static int kbc0_wr_req(const struct device *dev, enum lpc_peripheral_opcode op,
uint32_t *data)
{
struct kbc_regs *kbc_hw = (struct kbc_regs *)xec_kbc0_cfg.regbase;
volatile uint32_t __attribute__((unused)) dummy;
ARG_UNUSED(dev);
if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) {
/* Make sure kbc 8042 is on */
if (!(kbc_hw->KBC_CTRL & MCHP_KBC_CTRL_OBFEN)) {
return -ENOTSUP;
}
switch (op) {
case E8042_WRITE_KB_CHAR:
kbc_hw->EC_DATA = *data & 0xff;
break;
case E8042_WRITE_MB_CHAR:
kbc_hw->EC_AUX_DATA = *data & 0xff;
break;
case E8042_RESUME_IRQ:
mchp_xec_ecia_info_girq_src_clr(
xec_kbc0_cfg.ibf_ecia_info);
mchp_xec_ecia_info_girq_src_en(
xec_kbc0_cfg.ibf_ecia_info);
break;
case E8042_PAUSE_IRQ:
mchp_xec_ecia_info_girq_src_dis(
xec_kbc0_cfg.ibf_ecia_info);
break;
case E8042_CLEAR_OBF:
dummy = kbc_hw->HOST_AUX_DATA;
break;
case E8042_SET_FLAG:
/* FW shouldn't modify these flags directly */
*data &= ~(MCHP_KBC_STS_OBF | MCHP_KBC_STS_IBF |
MCHP_KBC_STS_AUXOBF);
kbc_hw->EC_KBC_STS |= *data;
break;
case E8042_CLEAR_FLAG:
/* FW shouldn't modify these flags directly */
*data |= (MCHP_KBC_STS_OBF | MCHP_KBC_STS_IBF |
MCHP_KBC_STS_AUXOBF);
kbc_hw->EC_KBC_STS &= ~(*data);
break;
default:
return -EINVAL;
}
} else {
return -ENOTSUP;
}
return 0;
}
static int connect_irq_kbc0(const struct device *dev)
{
/* clear GIRQ source */
mchp_xec_ecia_info_girq_src_clr(xec_kbc0_cfg.ibf_ecia_info);
mchp_xec_ecia_info_girq_src_clr(xec_kbc0_cfg.obe_ecia_info);
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_NODELABEL(kbc0), kbc_ibf, irq),
DT_IRQ_BY_NAME(DT_NODELABEL(kbc0), kbc_ibf, priority),
kbc0_ibf_isr,
DEVICE_DT_GET(DT_NODELABEL(espi0)),
0);
irq_enable(DT_IRQ_BY_NAME(DT_NODELABEL(kbc0), kbc_ibf, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_NODELABEL(kbc0), kbc_obe, irq),
DT_IRQ_BY_NAME(DT_NODELABEL(kbc0), kbc_obe, priority),
kbc0_obe_isr,
DEVICE_DT_GET(DT_NODELABEL(espi0)),
0);
irq_enable(DT_IRQ_BY_NAME(DT_NODELABEL(kbc0), kbc_obe, irq));
/* enable GIRQ sources */
mchp_xec_ecia_info_girq_src_en(xec_kbc0_cfg.ibf_ecia_info);
mchp_xec_ecia_info_girq_src_en(xec_kbc0_cfg.obe_ecia_info);
return 0;
}
static int init_kbc0(const struct device *dev)
{
struct espi_xec_config *const cfg = ESPI_XEC_CONFIG(dev);
struct espi_iom_regs *regs = (struct espi_iom_regs *)cfg->base_addr;
struct kbc_regs *kbc_hw = (struct kbc_regs *)xec_kbc0_cfg.regbase;
kbc_hw->KBC_CTRL |= MCHP_KBC_CTRL_AUXH;
kbc_hw->KBC_CTRL |= MCHP_KBC_CTRL_OBFEN;
/* This is the activate register, but the HAL has a funny name */
kbc_hw->KBC_PORT92_EN = MCHP_KBC_PORT92_EN;
regs->IOHBAR[IOB_KBC] = ESPI_XEC_KBC_BAR_ADDRESS |
MCHP_ESPI_IO_BAR_HOST_VALID;
return 0;
}
#undef CONNECT_IRQ_KBC0
#define CONNECT_IRQ_KBC0 connect_irq_kbc0
#undef INIT_KBC0
#define INIT_KBC0 init_kbc0
#endif /* CONFIG_ESPI_PERIPHERAL_8042_KBC */
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO
static const struct xec_acpi_ec_config xec_acpi_ec0_cfg = {
.regbase = DT_REG_ADDR(DT_NODELABEL(acpi_ec0)),
.ibf_ecia_info = DT_PROP_BY_IDX(DT_NODELABEL(acpi_ec0), girqs, 0),
.obe_ecia_info = DT_PROP_BY_IDX(DT_NODELABEL(acpi_ec0), girqs, 1),
};
static void acpi_ec0_ibf_isr(const struct device *dev)
{
struct espi_xec_data *const data =
(struct espi_xec_data *const)dev->data;
struct espi_event evt = { ESPI_BUS_PERIPHERAL_NOTIFICATION,
ESPI_PERIPHERAL_HOST_IO, ESPI_PERIPHERAL_NODATA
};
espi_send_callbacks(&data->callbacks, dev, evt);
/* clear GIRQ status */
mchp_xec_ecia_info_girq_src_clr(xec_acpi_ec0_cfg.ibf_ecia_info);
}
static void acpi_ec0_obe_isr(const struct device *dev)
{
/* disable and clear GIRQ status */
mchp_xec_ecia_info_girq_src_dis(xec_acpi_ec0_cfg.obe_ecia_info);
mchp_xec_ecia_info_girq_src_clr(xec_acpi_ec0_cfg.obe_ecia_info);
}
static int eacpi_rd_req(const struct device *dev,
enum lpc_peripheral_opcode op,
uint32_t *data)
{
ARG_UNUSED(dev);
ARG_UNUSED(op);
ARG_UNUSED(data);
return -EINVAL;
}
static int eacpi_wr_req(const struct device *dev,
enum lpc_peripheral_opcode op,
uint32_t *data)
{
ARG_UNUSED(dev);
ARG_UNUSED(op);
ARG_UNUSED(data);
return -EINVAL;
}
static int connect_irq_acpi_ec0(const struct device *dev)
{
mchp_xec_ecia_info_girq_src_clr(xec_acpi_ec0_cfg.ibf_ecia_info);
mchp_xec_ecia_info_girq_src_clr(xec_acpi_ec0_cfg.obe_ecia_info);
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_NODELABEL(acpi_ec0), acpi_ibf, irq),
DT_IRQ_BY_NAME(DT_NODELABEL(acpi_ec0), acpi_ibf, priority),
acpi_ec0_ibf_isr,
DEVICE_DT_GET(DT_NODELABEL(espi0)),
0);
irq_enable(DT_IRQ_BY_NAME(DT_NODELABEL(acpi_ec0), acpi_ibf, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_NODELABEL(acpi_ec0), acpi_obe, irq),
DT_IRQ_BY_NAME(DT_NODELABEL(acpi_ec0), acpi_obe, priority),
acpi_ec0_obe_isr,
DEVICE_DT_GET(DT_NODELABEL(espi0)),
0);
irq_enable(DT_IRQ_BY_NAME(DT_NODELABEL(acpi_ec0), acpi_obe, irq));
mchp_xec_ecia_info_girq_src_en(xec_acpi_ec0_cfg.ibf_ecia_info);
mchp_xec_ecia_info_girq_src_en(xec_acpi_ec0_cfg.obe_ecia_info);
return 0;
}
static int init_acpi_ec0(const struct device *dev)
{
struct espi_xec_config *const cfg = ESPI_XEC_CONFIG(dev);
struct espi_iom_regs *regs = (struct espi_iom_regs *)cfg->base_addr;
regs->IOHBAR[IOB_ACPI_EC0] = ESPI_XEC_ACPI_EC0_BAR_ADDRESS |
MCHP_ESPI_IO_BAR_HOST_VALID;
return 0;
}
#undef CONNECT_IRQ_ACPI_EC0
#define CONNECT_IRQ_ACPI_EC0 connect_irq_acpi_ec0
#undef INIT_ACPI_EC0
#define INIT_ACPI_EC0 init_acpi_ec0
#endif /* CONFIG_ESPI_PERIPHERAL_HOST_IO */
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT
static const struct xec_acpi_ec_config xec_acpi_ec1_cfg = {
.regbase = DT_REG_ADDR(DT_NODELABEL(acpi_ec1)),
.ibf_ecia_info = DT_PROP_BY_IDX(DT_NODELABEL(acpi_ec1), girqs, 0),
.obe_ecia_info = DT_PROP_BY_IDX(DT_NODELABEL(acpi_ec1), girqs, 1),
};
static void acpi_ec1_ibf_isr(const struct device *dev)
{
struct espi_xec_data *const data =
(struct espi_xec_data *const)dev->data;
struct espi_event evt = {
.evt_type = ESPI_BUS_PERIPHERAL_NOTIFICATION,
.evt_details = ESPI_PERIPHERAL_HOST_IO_PVT,
.evt_data = ESPI_PERIPHERAL_NODATA
};
espi_send_callbacks(&data->callbacks, dev, evt);
/* clear GIRQ status */
mchp_xec_ecia_info_girq_src_clr(xec_acpi_ec1_cfg.ibf_ecia_info);
}
static void acpi_ec1_obe_isr(const struct device *dev)
{
/* disable and clear GIRQ status */
mchp_xec_ecia_info_girq_src_dis(xec_acpi_ec1_cfg.obe_ecia_info);
mchp_xec_ecia_info_girq_src_clr(xec_acpi_ec1_cfg.obe_ecia_info);
}
static int connect_irq_acpi_ec1(const struct device *dev)
{
mchp_xec_ecia_info_girq_src_clr(xec_acpi_ec1_cfg.ibf_ecia_info);
mchp_xec_ecia_info_girq_src_clr(xec_acpi_ec1_cfg.obe_ecia_info);
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_NODELABEL(acpi_ec1), acpi_ibf, irq),
DT_IRQ_BY_NAME(DT_NODELABEL(acpi_ec1), acpi_ibf, priority),
acpi_ec1_ibf_isr,
DEVICE_DT_GET(DT_NODELABEL(espi0)),
0);
irq_enable(DT_IRQ_BY_NAME(DT_NODELABEL(acpi_ec1), acpi_ibf, irq));
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_NODELABEL(acpi_ec1), acpi_obe, irq),
DT_IRQ_BY_NAME(DT_NODELABEL(acpi_ec1), acpi_obe, priority),
acpi_ec1_obe_isr,
DEVICE_DT_GET(DT_NODELABEL(espi0)),
0);
irq_enable(DT_IRQ_BY_NAME(DT_NODELABEL(acpi_ec1), acpi_obe, irq));
mchp_xec_ecia_info_girq_src_en(xec_acpi_ec1_cfg.ibf_ecia_info);
mchp_xec_ecia_info_girq_src_en(xec_acpi_ec1_cfg.obe_ecia_info);
return 0;
}
static int init_acpi_ec1(const struct device *dev)
{
struct espi_xec_config *const cfg = ESPI_XEC_CONFIG(dev);
struct espi_iom_regs *regs = (struct espi_iom_regs *)cfg->base_addr;
regs->IOHBAR[IOB_ACPI_EC1] =
CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT_PORT_NUM |
MCHP_ESPI_IO_BAR_HOST_VALID;
regs->IOHBAR[IOB_MBOX] = ESPI_XEC_MBOX_BAR_ADDRESS |
MCHP_ESPI_IO_BAR_HOST_VALID;
return 0;
}
#undef CONNECT_IRQ_ACPI_EC1
#define CONNECT_IRQ_ACPI_EC1 connect_irq_acpi_ec1
#undef INIT_ACPI_EC1
#define INIT_ACPI_EC1 init_acpi_ec1
#endif /* CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT */
#ifdef CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80
struct xec_p80bd_config {
uintptr_t regbase;
uint32_t ecia_info;
};
static const struct xec_p80bd_config xec_p80bd0_cfg = {
.regbase = DT_REG_ADDR(DT_NODELABEL(p80bd0)),
.ecia_info = DT_PROP_BY_IDX(DT_NODELABEL(p80bd0), girqs, 0),
};
/*
* MEC172x P80 BIOS Debug Port hardware captures writes to its 4-byte I/O range
* Hardware provides status indicating byte lane(s) of each write.
* We must decode the byte lane information and produce one or more
* notification packets.
*/
static void p80bd0_isr(const struct device *dev)
{
struct espi_xec_data *const data =
(struct espi_xec_data *const)dev->data;
struct p80bd_regs *p80regs =
(struct p80bd_regs *)xec_p80bd0_cfg.regbase;
struct espi_event evt = { ESPI_BUS_PERIPHERAL_NOTIFICATION, 0,
ESPI_PERIPHERAL_NODATA };
int count = 8; /* limit ISR to 8 bytes */
uint32_t dattr = p80regs->EC_DA;
/* b[7:0]=8-bit value written, b[15:8]=attributes */
while ((dattr & MCHP_P80BD_ECDA_NE) && (count--)) { /* Not empty? */
/* espi_event protocol No Data value is 0 so pick a bit and
* set it. This depends on the application.
*/
evt.evt_data = (dattr & 0xffu) | BIT(16);
switch (dattr & MCHP_P80BD_ECDA_LANE_MSK) {
case MCHP_P80BD_ECDA_LANE_0:
evt.evt_details |= (ESPI_PERIPHERAL_INDEX_0 << 16) |
ESPI_PERIPHERAL_DEBUG_PORT80;
break;
case MCHP_P80BD_ECDA_LANE_1:
evt.evt_details |= (ESPI_PERIPHERAL_INDEX_1 << 16) |
ESPI_PERIPHERAL_DEBUG_PORT80;
break;
case MCHP_P80BD_ECDA_LANE_2:
break;
case MCHP_P80BD_ECDA_LANE_3:
break;
default:
break;
}
if (evt.evt_details) {
espi_send_callbacks(&data->callbacks, dev, evt);
evt.evt_details = 0;
}
}
/* clear GIRQ status */
mchp_xec_ecia_info_girq_src_clr(xec_p80bd0_cfg.ecia_info);
}
static int connect_irq_p80bd0(const struct device *dev)
{
mchp_xec_ecia_info_girq_src_clr(xec_p80bd0_cfg.ecia_info);
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(p80bd0)),
DT_IRQ(DT_NODELABEL(acpi_ec1), priority),
p80bd0_isr,
DEVICE_DT_GET(DT_NODELABEL(espi0)),
0);
irq_enable(DT_IRQN(DT_NODELABEL(p80bd0)));
mchp_xec_ecia_info_girq_src_en(xec_p80bd0_cfg.ecia_info);
return 0;
}
static int init_p80bd0(const struct device *dev)
{
struct espi_xec_config *const cfg = ESPI_XEC_CONFIG(dev);
struct espi_iom_regs *regs = (struct espi_iom_regs *)cfg->base_addr;
struct p80bd_regs *p80bd_hw =
(struct p80bd_regs *)xec_p80bd0_cfg.regbase;
regs->IOHBAR[IOB_P80BD] = ESPI_XEC_PORT80_BAR_ADDRESS |
MCHP_ESPI_IO_BAR_HOST_VALID;
p80bd_hw->ACTV = 1;
p80bd_hw->STS_IEN = MCHP_P80BD_SI_THR_IEN;
return 0;
}
#undef CONNECT_IRQ_P80BD0
#define CONNECT_IRQ_P80BD0 connect_irq_p80bd0
#undef INIT_P80BD0
#define INIT_P80BD0 init_p80bd0
#endif /* CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80 */
#ifdef CONFIG_ESPI_PERIPHERAL_UART
#if CONFIG_ESPI_PERIPHERAL_UART_SOC_MAPPING == 0
int init_uart0(const struct device *dev)
{
struct espi_xec_config *const cfg = ESPI_XEC_CONFIG(dev);
struct espi_iom_regs *regs = (struct espi_iom_regs *)cfg->base_addr;
regs->IOHBAR[IOB_UART0] = ESPI_XEC_UART0_BAR_ADDRESS |
MCHP_ESPI_IO_BAR_HOST_VALID;
return 0;
}
#undef INIT_UART0
#define INIT_UART0 init_uart0
#elif CONFIG_ESPI_PERIPHERAL_UART_SOC_MAPPING == 1
int init_uart1(const struct device *dev)
{
struct espi_xec_config *const cfg = ESPI_XEC_CONFIG(dev);
struct espi_iom_regs *regs = (struct espi_iom_regs *)cfg->base_addr;
regs->IOHBAR[IOB_UART1] = ESPI_XEC_UART0_BAR_ADDRESS |
MCHP_ESPI_IO_BAR_HOST_VALID;
return 0;
}
#undef INIT_UART1
#define INIT_UART1 init_uart1
#endif /* CONFIG_ESPI_PERIPHERAL_UART_SOC_MAPPING */
#endif /* CONFIG_ESPI_PERIPHERAL_UART */
typedef int (*host_dev_irq_connect)(const struct device *dev);
static const host_dev_irq_connect hdic_tbl[] = {
CONNECT_IRQ_MBOX0,
CONNECT_IRQ_KBC0,
CONNECT_IRQ_ACPI_EC0,
CONNECT_IRQ_ACPI_EC1,
CONNECT_IRQ_ACPI_EC2,
CONNECT_IRQ_ACPI_EC3,
CONNECT_IRQ_ACPI_EC4,
CONNECT_IRQ_ACPI_PM1,
CONNECT_IRQ_EMI0,
CONNECT_IRQ_EMI1,
CONNECT_IRQ_EMI2,
CONNECT_IRQ_RTC0,
CONNECT_IRQ_P80BD0,
};
typedef int (*host_dev_init)(const struct device *dev);
static const host_dev_init hd_init_tbl[] = {
INIT_MBOX0,
INIT_KBC0,
INIT_ACPI_EC0,
INIT_ACPI_EC1,
INIT_ACPI_EC2,
INIT_ACPI_EC3,
INIT_ACPI_EC4,
INIT_ACPI_PM1,
INIT_EMI0,
INIT_EMI1,
INIT_EMI2,
INIT_RTC0,
INIT_P80BD0,
INIT_UART0,
INIT_UART1,
};
int xec_host_dev_connect_irqs(const struct device *dev)
{
int ret = 0;
for (int i = 0; i < ARRAY_SIZE(hdic_tbl); i++) {
if (hdic_tbl[i] == NULL) {
continue;
}
ret = hdic_tbl[i](dev);
if (ret < 0) {
break;
}
}
return ret;
}
int xec_host_dev_init(const struct device *dev)
{
int ret = 0;
for (int i = 0; i < ARRAY_SIZE(hd_init_tbl); i++) {
if (hd_init_tbl[i] == NULL) {
continue;
}
ret = hd_init_tbl[i](dev);
if (ret < 0) {
break;
}
}
return ret;
}
#ifdef CONFIG_ESPI_PERIPHERAL_CHANNEL
typedef int (*xec_lpc_req)(const struct device *,
enum lpc_peripheral_opcode,
uint32_t *);
struct espi_lpc_req {
uint16_t opcode_start;
uint16_t opcode_max;
xec_lpc_req rd_req;
xec_lpc_req wr_req;
};
static const struct espi_lpc_req espi_lpc_req_tbl[] = {
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
{ E8042_START_OPCODE, E8042_MAX_OPCODE, kbc0_rd_req, kbc0_wr_req },
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO
{ EACPI_START_OPCODE, EACPI_MAX_OPCODE, eacpi_rd_req, eacpi_wr_req },
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE
{ ECUSTOM_START_OPCODE, ECUSTOM_MAX_OPCODE, ecust_rd_req, ecust_wr_req},
#endif
};
static int espi_xec_lpc_req(const struct device *dev,
enum lpc_peripheral_opcode op,
uint32_t *data, uint8_t write)
{
ARG_UNUSED(dev);
for (int i = 0; i < ARRAY_SIZE(espi_lpc_req_tbl); i++) {
const struct espi_lpc_req *req = &espi_lpc_req_tbl[i];
if ((op >= req->opcode_start) && (op <= req->opcode_max)) {
if (write) {
return req->wr_req(dev, op, data);
} else {
return req->rd_req(dev, op, data);
}
}
}
return -ENOTSUP;
}
/* dev = pointer to espi0 device */
int espi_xec_read_lpc_request(const struct device *dev,
enum lpc_peripheral_opcode op,
uint32_t *data)
{
return espi_xec_lpc_req(dev, op, data, 0);
}
int espi_xec_write_lpc_request(const struct device *dev,
enum lpc_peripheral_opcode op,
uint32_t *data)
{
return espi_xec_lpc_req(dev, op, data, 1);
}
#else
int espi_xec_write_lpc_request(const struct device *dev,
enum lpc_peripheral_opcode op,
uint32_t *data)
{
ARG_UNUSED(dev);
ARG_UNUSED(op);
ARG_UNUSED(data);
return -ENOTSUP;
}
int espi_xec_read_lpc_request(const struct device *dev,
enum lpc_peripheral_opcode op,
uint32_t *data)
{
ARG_UNUSED(dev);
ARG_UNUSED(op);
ARG_UNUSED(data);
return -ENOTSUP;
}
#endif /* CONFIG_ESPI_PERIPHERAL_CHANNEL */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,119 @@
/*
* Copyright (c) 2021 Microchip Technology Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_ESPI_MCHP_XEC_ESPI_V2_H_
#define ZEPHYR_DRIVERS_ESPI_MCHP_XEC_ESPI_V2_H_
#include <stdint.h>
#include <device.h>
#include <drivers/espi.h>
#define ESPI_XEC_V2_DEBUG 1
struct espi_isr {
uint8_t girq_id;
uint8_t girq_pos;
void (*the_isr)(const struct device *dev);
};
struct espi_vw_isr {
uint8_t signal;
uint8_t girq_id;
uint8_t girq_pos;
void (*the_isr)(int girq, int bpos, void *dev);
};
struct espi_xec_irq_info {
uint8_t gid; /* GIRQ id [8, 26] */
uint8_t gpos; /* bit position in GIRQ [0, 31] */
uint8_t anid; /* Aggregated GIRQ NVIC number */
uint8_t dnid; /* Direct GIRQ NVIC number */
};
struct espi_xec_config {
uint32_t base_addr;
uint32_t vw_base_addr;
uint8_t pcr_idx;
uint8_t pcr_bitpos;
const struct espi_xec_irq_info *irq_info_list;
uint8_t irq_info_size;
};
#define ESPI_XEC_CONFIG(dev) \
((struct espi_xec_config * const)(dev)->config)
struct espi_xec_data {
sys_slist_t callbacks;
struct k_sem tx_lock;
struct k_sem rx_lock;
struct k_sem flash_lock;
uint8_t plt_rst_asserted;
uint8_t espi_rst_asserted;
uint8_t sx_state;
#ifdef ESPI_XEC_V2_DEBUG
uint32_t espi_rst_count;
#endif
};
#define ESPI_XEC_DATA(dev) \
((struct espi_xec_data * const)(dev)->data)
struct xec_signal {
uint8_t xec_reg_idx;
uint8_t bit;
uint8_t dir;
};
enum mchp_msvw_regs {
MCHP_MSVW00,
MCHP_MSVW01,
MCHP_MSVW02,
MCHP_MSVW03,
MCHP_MSVW04,
MCHP_MSVW05,
MCHP_MSVW06,
MCHP_MSVW07,
MCHP_MSVW08,
};
enum mchp_smvw_regs {
MCHP_SMVW00,
MCHP_SMVW01,
MCHP_SMVW02,
MCHP_SMVW03,
MCHP_SMVW04,
MCHP_SMVW05,
MCHP_SMVW06,
MCHP_SMVW07,
MCHP_SMVW08,
};
enum xec_espi_girq_idx {
pc_girq_idx = 0,
bm1_girq_idx,
bm2_girq_idx,
ltr_girq_idx,
oob_up_girq_idx,
oob_dn_girq_idx,
fc_girq_idx,
rst_girq_idx,
vw_ch_en_girq_idx,
max_girq_idx,
};
int xec_host_dev_init(const struct device *dev);
int xec_host_dev_connect_irqs(const struct device *dev);
int espi_xec_read_lpc_request(const struct device *dev,
enum lpc_peripheral_opcode op,
uint32_t *data);
int espi_xec_write_lpc_request(const struct device *dev,
enum lpc_peripheral_opcode op,
uint32_t *data);
#endif /* ZEPHYR_DRIVERS_ESPI_MCHP_XEC_ESPI_V2_H_ */