diff --git a/drivers/espi/CMakeLists.txt b/drivers/espi/CMakeLists.txt index 82e257098f38fd..cfdf84fd7575dd 100644 --- a/drivers/espi/CMakeLists.txt +++ b/drivers/espi/CMakeLists.txt @@ -7,7 +7,8 @@ zephyr_library_sources_ifdef(CONFIG_ESPI_NPCX espi_npcx.c) 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_SAF_XEC 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) zephyr_library_sources_ifdef(CONFIG_ESPI_IT8XXX2 espi_it8xxx2.c) +zephyr_library_sources_ifdef(CONFIG_ESPI_SAF_XEC_V2 espi_saf_mchp_xec_v2.c) diff --git a/drivers/espi/Kconfig b/drivers/espi/Kconfig index 3c4de413c86655..f8ee937af57529 100644 --- a/drivers/espi/Kconfig +++ b/drivers/espi/Kconfig @@ -12,8 +12,6 @@ if ESPI source "drivers/espi/Kconfig.xec" -source "drivers/espi/Kconfig.xec_v2" - source "drivers/espi/Kconfig.npcx" source "drivers/espi/Kconfig.espi_emul" @@ -178,4 +176,19 @@ config ESPI_OOB_CHANNEL_RX_ASYNC Enables asynchronous handling for host-initiated OOB traffic. Otherwise OOB traffic is assumed to be always client-initiated. +config ESPI_SAF + bool "ESPI SAF driver" + depends on ESPI_FLASH_CHANNEL + help + Enable Slave Attached Flash eSPI driver. SAF depends upon ESPI 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. SAF driver must + initialize after the ESPI driver. + endif # ESPI diff --git a/drivers/espi/Kconfig.xec b/drivers/espi/Kconfig.xec index b6fde723b71da8..585731dbdd3205 100644 --- a/drivers/espi/Kconfig.xec +++ b/drivers/espi/Kconfig.xec @@ -5,11 +5,17 @@ config ESPI_XEC bool "XEC Microchip ESPI driver" - depends on SOC_SERIES_MEC1501X + depends on DT_HAS_MICROCHIP_XEC_ESPI_SAF_ENABLED help Enable the Microchip XEC ESPI driver for MEC15xx family. -if ESPI_XEC +config ESPI_XEC_V2 + bool "XEC Microchip ESPI V2 driver" + depends on DT_HAS_MICROCHIP_XEC_ESPI_SAF_V2_ENABLED + help + Enable the Microchip XEC ESPI driver for MEC172x series. + +if ESPI_XEC || ESPI_XEC_V2 config ESPI_OOB_CHANNEL default y @@ -55,6 +61,93 @@ config ESPI_FLASH_BUFFER_SIZE Use maximum RAM buffer size defined by spec but allow applications to override if eSPI host doesn't support it. +config ESPI_SAF_XEC + bool "XEC Microchip ESPI SAF driver" + depends on SOC_SERIES_MEC1501X + help + Enable the Microchip XEC SAF ESPI driver for MEC15xx family. + +config ESPI_SAF_XEC_V2 + bool "XEC Microchip ESPI SAF V2 driver" + depends on SOC_SERIES_MEC172X + help + Enable the Microchip XEC SAF ESPI driver for MEC172x series. + +endif #ESPI_XEC + +if ESPI_XEC_V2 + +config ESPI_XEC_PERIPHERAL_ACPI_SHD_MEM_SIZE + int "Host I/O peripheral port size for shared memory in MEC172X series" + depends on ESPI_XEC_V2 || ESPI_PERIPHERAL_ACPI_SHM_REGION + default 256 + help + This is the port size used by the Host and EC to communicate over + the shared memory region to return the ACPI response data. + +config ESPI_XEC_PERIPHERAL_HOST_CMD_PARAM_SIZE + int "Host I/O peripheral port size for ec host command in MEC172X series" + depends on ESPI_XEC_V2 || ESPI_PERIPHERAL_EC_HOST_CMD + default 256 + help + This is the port size used by the Host and EC to communicate over + the shared memory region to return the host command parameter data. + +config ESPI_PERIPHERAL_8042_KBC + default y + +if ESPI_PERIPHERAL_CHANNEL + +config ESPI_PERIPHERAL_XEC_MAILBOX + bool "SoC Mailbox over eSPI" + 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" + 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" + 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" + 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" + 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" + 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" + 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" + help + Enable EMI 2 interface accessible via Host I/O over the + ESPI Peripheral Channel. + +endif #ESPI_PERIPHERAL_CHANNEL + config ESPI_SAF bool "XEC Microchip ESPI SAF driver" depends on ESPI_FLASH_CHANNEL @@ -69,4 +162,26 @@ config ESPI_SAF_INIT_PRIORITY help Driver initialization priority for eSPI SAF driver. -endif #ESPI_XEC +config ESPI_PERIPHERAL_ACPI_EC_IBF_EVT_DATA + bool "Read ACPI EC Event Data in IBF ISR" + depends on ESPI_PERIPHERAL_CHANNEL + help + Enable reading event data in ACPI EC IBF ISR. This is used in OS + environment where application expects IBF ISR to read data and pass + to callback. + +endif #ESPI_XEC_V2 + +if ESPI_XEC_V2 && ESPI_PERIPHERAL_8042_KBC + +config ESPI_PERIPHERAL_KBC_IBF_EVT_DATA + bool "KBC event data format in IBF" + help + Enable espi_evt_data_kbc format for encoding event in KBC IBF ISR + +config ESPI_PERIPHERAL_KBC_OBE_CBK + bool "KBC OBE Callback" + help + Enable KBC OBE callback from OBE ISR + +endif #ESPI_XEC_V2 && ESPI_PERIPHERAL_8042_KBC diff --git a/drivers/espi/Kconfig.xec_v2 b/drivers/espi/Kconfig.xec_v2 deleted file mode 100644 index e7bb7154038d8b..00000000000000 --- a/drivers/espi/Kconfig.xec_v2 +++ /dev/null @@ -1,169 +0,0 @@ -# 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. - -config ESPI_XEC_PERIPHERAL_ACPI_SHD_MEM_SIZE - int "Host I/O peripheral port size for shared memory in MEC172X series" - depends on ESPI_XEC_V2 || ESPI_PERIPHERAL_ACPI_SHM_REGION - default 256 - help - This is the port size used by the Host and EC to communicate over - the shared memory region to return the ACPI response data. - -config ESPI_XEC_PERIPHERAL_HOST_CMD_PARAM_SIZE - int "Host I/O peripheral port size for ec host command in MEC172X series" - depends on ESPI_XEC_V2 || ESPI_PERIPHERAL_EC_HOST_CMD - default 256 - help - This is the port size used by the Host and EC to communicate over - the shared memory region to return the host command parameter data. - -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 - 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. - -config ESPI_PERIPHERAL_ACPI_EC_IBF_EVT_DATA - bool "Read ACPI EC Event Data in IBF ISR" - depends on ESPI_PERIPHERAL_CHANNEL - help - Enable reading event data in ACPI EC IBF ISR. This is used in OS - environment where application expects IBF ISR to read data and pass - to callback. - -endif #ESPI_XEC_V2 - -if ESPI_PERIPHERAL_8042_KBC - -config ESPI_PERIPHERAL_KBC_IBF_EVT_DATA - bool "KBC event data format in IBF" - help - Enable espi_evt_data_kbc format for encoding event in KBC IBF ISR - -config ESPI_PERIPHERAL_KBC_OBE_CBK - bool "KBC OBE Callback" - help - Enable KBC OBE callback from OBE ISR - -endif #ESPI_PERIPHERAL_8042_KBC diff --git a/drivers/espi/espi_saf_mchp_xec_v2.c b/drivers/espi/espi_saf_mchp_xec_v2.c new file mode 100644 index 00000000000000..aa7ea6905816de --- /dev/null +++ b/drivers/espi/espi_saf_mchp_xec_v2.c @@ -0,0 +1,1175 @@ +/* + * Copyright (c) 2019 Intel Corporation + * Copyright (c) 2022 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT microchip_xec_espi_saf_v2 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "espi_mchp_xec_v2.h" +#include "espi_utils.h" +LOG_MODULE_REGISTER(espi_saf, CONFIG_ESPI_LOG_LEVEL); + +/* common clock control device node for all Microchip XEC chips */ +#define MCHP_XEC_CLOCK_CONTROL_NODE DT_NODELABEL(pcr) + +/* SAF EC Portal read/write flash access limited to 1-64 bytes */ +#define MAX_SAF_ECP_BUFFER_SIZE 64ul + +/* 1 second maximum for flash operations */ +#define MAX_SAF_FLASH_TIMEOUT 125000ul /* 1000ul */ + +#define MAX_SAF_FLASH_TIMEOUT_MS 1000ul + +/* 64 bytes @ 24MHz quad is approx. 6 us */ +#define SAF_WAIT_INTERVAL 8 + +/* After 8 wait intervals yield */ +#define SAF_YIELD_THRESHOLD 64 + +/* Get QMSPI 0 encoded GIRQ information */ +#define XEC_QMSPI_ENC_GIRQ \ + DT_PROP_BY_IDX(DT_INST(0, microchip_xec_qmspi_ldma), girqs, 0) + +#define XEC_QMSPI_GIRQ MCHP_XEC_ECIA_GIRQ(XEC_QMSPI_ENC_GIRQ) +#define XEC_QMSPI_GIRQ_POS MCHP_XEC_ECIA_GIRQ_POS(XEC_QMSPI_ENC_GIRQ) + +#define XEC_SAF_DONE_ENC_GIRQ DT_INST_PROP_BY_IDX(0, girqs, 0) +#define XEC_SAF_ERR_ENC_GIRQ DT_INST_PROP_BY_IDX(0, girqs, 1) + +#define XEC_SAF_DONE_GIRQ MCHP_XEC_ECIA_GIRQ(XEC_SAF_DONE_ENC_GIRQ) +#define XEC_SAF_DONE_GIRQ_POS MCHP_XEC_ECIA_GIRQ_POS(XEC_SAF_ERR_ENC_GIRQ) + +/* + * SAF configuration from Device Tree + * SAF controller register block base address + * QMSPI controller register block base address + * SAF communications register block base address + * Flash STATUS1 poll timeout in 32KHz periods + * Flash consecutive read timeout in units of 20 ns + * Delay before first Poll-1 command after suspend in 20 ns units + * Hold off suspend for this interval if erase or program in 32KHz periods. + * Add delay between Poll STATUS1 commands in 20 ns units. + */ +struct espi_saf_xec_config { + struct mchp_espi_saf * const saf_base; + struct qmspi_regs * const qmspi_base; + struct mchp_espi_saf_comm * const saf_comm_base; + struct espi_iom_regs * const iom_base; + void (*irq_config_func)(void); + uint32_t poll_timeout; + uint32_t consec_rd_timeout; + uint32_t sus_chk_delay; + uint16_t sus_rsm_interval; + uint16_t poll_interval; + uint8_t pcr_idx; + uint8_t pcr_pos; + uint8_t irq_info_size; + uint8_t rsvd1; + const struct espi_xec_irq_info *irq_info_list; +}; + +struct espi_saf_xec_data { + struct k_sem ecp_lock; + uint32_t hwstatus; + sys_slist_t callbacks; +}; + +/* EC portal local flash r/w buffer */ +static uint32_t slave_mem[MAX_SAF_ECP_BUFFER_SIZE]; + +/* + * @brief eSPI SAF configuration + */ + +static inline void mchp_saf_cs_descr_wr(struct mchp_espi_saf *regs, uint8_t cs, + uint32_t val) +{ + regs->SAF_CS_OP[cs].OP_DESCR = val; +} + +static inline void mchp_saf_poll2_mask_wr(struct mchp_espi_saf *regs, uint8_t cs, + uint16_t val) +{ + LOG_DBG("%s cs: %d mask %x", __func__, cs, val); + if (cs == 0) { + regs->SAF_CS0_CFG_P2M = val; + } else { + regs->SAF_CS1_CFG_P2M = val; + } +} + +static inline void mchp_saf_cm_prefix_wr(struct mchp_espi_saf *regs, uint8_t cs, + uint16_t val) +{ + if (cs == 0) { + regs->SAF_CS0_CM_PRF = val; + } else { + regs->SAF_CS1_CM_PRF = val; + } +} + +/* + * Initialize SAF flash protection regions. + * SAF HW implements 17 protection regions. + * At least one protection region must be configured to allow + * EC access to the local flash through the EC Portal. + * Each protection region is composed of 4 32-bit registers + * Start bits[19:0] = bits[31:12] region start address (4KB boundaries) + * Limit bits[19:0] = bits[31:12] region limit address (4KB boundaries) + * Write protect b[7:0] = masters[7:0] allow write/erase. 1=allowed + * Read protetc b[7:0] = masters[7:0] allow read. 1=allowed + * + * This routine configures protection region 0 for full flash array + * address range and read-write-erase for all masters. + * This routine must be called AFTER the flash configuration size/limit and + * threshold registers have been programmed. + * + * POR default values: + * Start = 0x7ffff + * Limit = 0 + * Write Prot = 0x01 Master 0 always granted write/erase + * Read Prot = 0x01 Master 0 always granted read + * + * Sample code configures PR[0] + * Start = 0 + * Limit = 0x7ffff + * WR = 0xFF + * RD = 0xFF + */ +static void saf_protection_regions_init(struct mchp_espi_saf *regs) +{ + LOG_DBG("%s", __func__); + + for (size_t n = 0; n < MCHP_ESPI_SAF_PR_MAX; n++) { + if (n == 0) { + regs->SAF_PROT_RG[0].START = 0U; + regs->SAF_PROT_RG[0].LIMIT = + regs->SAF_FL_CFG_SIZE_LIM >> 12; + regs->SAF_PROT_RG[0].WEBM = MCHP_SAF_MSTR_ALL; + regs->SAF_PROT_RG[0].RDBM = MCHP_SAF_MSTR_ALL; + } else { + regs->SAF_PROT_RG[n].START = + MCHP_SAF_PROT_RG_START_DFLT; + regs->SAF_PROT_RG[n].LIMIT = + MCHP_SAF_PROT_RG_LIMIT_DFLT; + regs->SAF_PROT_RG[n].WEBM = 0U; + regs->SAF_PROT_RG[n].RDBM = 0U; + } + + LOG_DBG("PROT[%d] START %x", n, regs->SAF_PROT_RG[n].START); + LOG_DBG("PROT[%d] LIMIT %x", n, regs->SAF_PROT_RG[n].LIMIT); + LOG_DBG("PROT[%d] WEBM %x", n, regs->SAF_PROT_RG[n].WEBM); + LOG_DBG("PROT[%d] RDBM %x", n, regs->SAF_PROT_RG[n].RDBM); + } +} + +static int qmspi_freq_div(uint32_t freqhz, uint32_t *fdiv) +{ + clock_control_subsys_t clkss = + (clock_control_subsys_t)(MCHP_XEC_PCR_CLK_PERIPH_FAST); + uint32_t clk = 0u; + + if (!fdiv) { + return -EINVAL; + } + + if (clock_control_get_rate(DEVICE_DT_GET(MCHP_XEC_CLOCK_CONTROL_NODE), + (clock_control_subsys_t)clkss, &clk)) { + return -EIO; + } + + *fdiv = 0u; /* maximum divider = 0x10000 */ + if (freqhz) { + *fdiv = clk / freqhz; + } + + return 0u; +} + +static int qmspi_freq_div_from_mhz(uint32_t freqmhz, uint32_t *fdiv) +{ + uint32_t freqhz = freqmhz * 1000000u; + + return qmspi_freq_div(freqhz, fdiv); +} + +/* + * Take over and re-initialize QMSPI for use by SAF HW engine. + * When SAF is activated, QMSPI registers are controlled by SAF + * HW engine. CPU no longer has access to QMSPI registers. + * 1. Save QMSPI driver frequency divider, SPI signalling mode, and + * chip select timing. + * 2. Put QMSPI controller in a known state by performing a soft reset. + * 3. Clear QMSPI GIRQ status + * 4. Configure QMSPI interface control for SAF. + * 5. Load flash device independent (generic) descriptors. + * 6. Enable transfer done interrupt in QMSPI + * 7. Enable QMSPI SAF mode + * 8. If user configuration overrides frequency, signalling mode, + * or chip select timing derive user values. + * 9. Program QMSPI MODE and CSTIM registers with activate set. + */ +static int saf_qmspi_init(const struct espi_saf_xec_config *xcfg, + const struct espi_saf_cfg *cfg) +{ + uint32_t qmode, qfdiv, cstim, n; + struct qmspi_regs * const qregs = xcfg->qmspi_base; + struct mchp_espi_saf * const regs = xcfg->saf_base; + const struct espi_saf_hw_cfg *hwcfg = &cfg->hwcfg; + + qmode = qregs->MODE; + if (!(qmode & MCHP_QMSPI_M_ACTIVATE)) { + return -EAGAIN; + } + + qmode = qregs->MODE & (MCHP_QMSPI_M_FDIV_MASK | MCHP_QMSPI_M_SIG_MASK); + cstim = qregs->CSTM; + qregs->MODE = MCHP_QMSPI_M_SRST; + qregs->STS = MCHP_QMSPI_STS_RW1C_MASK; + + mchp_soc_ecia_girq_src_dis(XEC_QMSPI_GIRQ, XEC_QMSPI_GIRQ_POS); + mchp_soc_ecia_girq_src_clr(XEC_QMSPI_GIRQ, XEC_QMSPI_GIRQ_POS); + + qregs->IFCTRL = + (MCHP_QMSPI_IFC_WP_OUT_HI | MCHP_QMSPI_IFC_WP_OUT_EN | + MCHP_QMSPI_IFC_HOLD_OUT_HI | MCHP_QMSPI_IFC_HOLD_OUT_EN); + + for (n = 0; n < MCHP_SAF_NUM_GENERIC_DESCR; n++) { + qregs->DESCR[MCHP_SAF_CM_EXIT_START_DESCR + n] = + hwcfg->generic_descr[n]; + } + + /* SAF HW uses QMSPI interrupt signal */ + qregs->IEN = MCHP_QMSPI_IEN_XFR_DONE; + + qmode |= (MCHP_QMSPI_M_SAF_DMA_MODE_EN | MCHP_QMSPI_M_CS0 | + MCHP_QMSPI_M_ACTIVATE); + + if (hwcfg->flags & MCHP_SAF_HW_CFG_FLAG_CPHA) { + qmode = (qmode & ~(MCHP_QMSPI_M_SIG_MASK)) | + ((hwcfg->qmspi_cpha << MCHP_QMSPI_M_SIG_POS) & + MCHP_QMSPI_M_SIG_MASK); + } + + + /* Copy QMSPI frequency divider into SAF CS0 and CS1 QMSPI frequency + * dividers. SAF HW uses CS0/CS1 divider register fields to overwrite + * QMSPI frequency divider in QMSPI.Mode register. Later we will update + * SAF CS0/CS1 SPI frequency dividers based on flash configuration. + */ + qfdiv = (qmode & MCHP_QMSPI_M_FDIV_MASK) >> MCHP_QMSPI_M_FDIV_POS; + qfdiv = qfdiv | (qfdiv << 16); /* read and rest clock dividers */ + regs->SAF_CLKDIV_CS0 = qfdiv; + regs->SAF_CLKDIV_CS1 = qfdiv; + + if (hwcfg->flags & MCHP_SAF_HW_CFG_FLAG_CSTM) { + cstim = hwcfg->qmspi_cs_timing; + } + + /* MEC172x SAF uses TX LDMA channel 0 in non-descriptor mode. + * SAF HW writes QMSPI.Control and TX LDMA channel 0 registers + * to transmit opcode, address, and data. We configure must + * configure TX LDMA channel 0 control register. We believe SAF + * HW will set bit[6] to 1. + */ + qregs->LDTX[0].CTRL = MCHP_QMSPI_LDC_EN | MCHP_QMSPI_LDC_RS_EN | MCHP_QMSPI_LDC_ASZ_4; + + qmode |= MCHP_QMSPI_M_LDMA_RX_EN | MCHP_QMSPI_M_LDMA_TX_EN; + + qregs->MODE = qmode; + qregs->CSTM = cstim; + + return 0; +} + +/* + * Registers at offsets: + * SAF Poll timeout @ 0x194. Hard coded to 0x28000. Default value = 0. + * recommended value = 0x28000 32KHz clocks (5 seconds). b[17:0] + * SAF Poll interval @ 0x198. Hard coded to 0 + * Default value = 0. Recommended = 0. b[15:0] + * SAF Suspend/Resume Interval @ 0x19c. Hard coded to 0x8 + * Default value = 0x01. Min time erase/prog in 32KHz units. + * SAF Consecutive Read Timeout @ 0x1a0. Hard coded to 0x2. b[15:0] + * Units of MCLK. Recommend < 20us. b[19:0] + * SAF Suspend Check Delay @ 0x1ac. Not touched. + * Default = 0. Recommend = 20us. Units = MCLK. b[19:0] + */ +static void saf_flash_timing_init(struct mchp_espi_saf * const regs, + const struct espi_saf_xec_config *cfg) +{ + LOG_DBG("%s\n", __func__); + regs->SAF_POLL_TMOUT = cfg->poll_timeout; + regs->SAF_POLL_INTRVL = cfg->poll_interval; + regs->SAF_SUS_RSM_INTRVL = cfg->sus_rsm_interval; + regs->SAF_CONSEC_RD_TMOUT = cfg->consec_rd_timeout; + regs->SAF_SUS_CHK_DLY = cfg->sus_chk_delay; + LOG_DBG("SAF_POLL_TMOUT %x\n", regs->SAF_POLL_TMOUT); + LOG_DBG("SAF_POLL_INTRVL %x\n", regs->SAF_POLL_INTRVL); + LOG_DBG("SAF_SUS_RSM_INTRVL %x\n", regs->SAF_SUS_RSM_INTRVL); + LOG_DBG("SAF_CONSEC_RD_TMOUT %x\n", regs->SAF_CONSEC_RD_TMOUT); + LOG_DBG("SAF_SUS_CHK_DLY %x\n", regs->SAF_SUS_CHK_DLY); +} + +/* + * Disable DnX bypass feature. + */ +static void saf_dnx_bypass_init(struct mchp_espi_saf * const regs) +{ + regs->SAF_DNX_PROT_BYP = 0; + regs->SAF_DNX_PROT_BYP = 0xffffffff; +} + +/* + * Bitmap of flash erase size from 1KB up to 128KB. + * eSPI SAF specification requires 4KB erase support. + * MCHP SAF supports 4KB, 32KB, and 64KB. + * Only report 32KB and 64KB to Host if supported by both + * flash devices. + */ +static int saf_init_erase_block_size(const struct device *dev, const struct espi_saf_cfg *cfg) +{ + const struct espi_saf_xec_config * const xcfg = dev->config; + struct espi_iom_regs * const espi_iom = xcfg->iom_base; + struct espi_saf_flash_cfg *fcfg = cfg->flash_cfgs; + uint32_t opb = fcfg->opb; + uint8_t erase_bitmap = MCHP_ESPI_SERASE_SZ_4K; + + LOG_DBG("%s\n", __func__); + + if (cfg->nflash_devices > 1) { + fcfg++; + opb &= fcfg->opb; + } + + if ((opb & MCHP_SAF_CS_OPB_ER0_MASK) == 0) { + /* One or both do not support 4KB erase! */ + return -EINVAL; + } + + if (opb & MCHP_SAF_CS_OPB_ER1_MASK) { + erase_bitmap |= MCHP_ESPI_SERASE_SZ_32K; + } + + if (opb & MCHP_SAF_CS_OPB_ER2_MASK) { + erase_bitmap |= MCHP_ESPI_SERASE_SZ_64K; + } + + espi_iom->SAFEBS = erase_bitmap; + + return 0; +} + +/* + * Set the continuous mode prefix and 4-byte address mode bits + * based upon the flash configuration information. + * Updates: + * SAF Flash Config Poll2 Mask @ 0x1A4 + * SAF Flash Config Special Mode @ 0x1B0 + * SAF Flash Misc Config @ 0x38 + */ +static void saf_flash_misc_cfg(struct mchp_espi_saf * const regs, uint8_t cs, + const struct espi_saf_flash_cfg *fcfg) +{ + uint32_t d, v; + + d = regs->SAF_FL_CFG_MISC; + + v = MCHP_SAF_FL_CFG_MISC_CS0_CPE; + if (cs) { + v = MCHP_SAF_FL_CFG_MISC_CS1_CPE; + } + + /* Does this flash device require a prefix for continuous mode? */ + if (fcfg->cont_prefix != 0) { + d |= v; + } else { + d &= ~v; + } + + v = MCHP_SAF_FL_CFG_MISC_CS0_4BM; + if (cs) { + v = MCHP_SAF_FL_CFG_MISC_CS1_4BM; + } + + /* Use 32-bit addressing for this flash device? */ + if (fcfg->flags & MCHP_FLASH_FLAG_ADDR32) { + d |= v; + } else { + d &= ~v; + } + + regs->SAF_FL_CFG_MISC = d; + LOG_DBG("%s SAF_FL_CFG_MISC: %x", __func__, d); +} + +static void saf_flash_pd_cfg(struct mchp_espi_saf * const regs, uint8_t cs, + const struct espi_saf_flash_cfg *fcfg) +{ + uint32_t pdval = 0u; + uint32_t msk = 0u; + + if (cs == 0) { + msk = BIT(SAF_PWRDN_CTRL_CS0_PD_EN_POS) | BIT(SAF_PWRDN_CTRL_CS0_PD_EN_POS); + if (fcfg->flags & MCHP_FLASH_FLAG_V2_PD_CS0_EN) { + pdval |= BIT(SAF_PWRDN_CTRL_CS0_PD_EN_POS); + } + if (fcfg->flags & MCHP_FLASH_FLAG_V2_PD_CS0_EC_WK_EN) { + pdval |= BIT(SAF_PWRDN_CTRL_CS0_WPA_EN_POS); + } + } else { + msk = BIT(SAF_PWRDN_CTRL_CS1_PD_EN_POS) | BIT(SAF_PWRDN_CTRL_CS1_PD_EN_POS); + if (fcfg->flags & MCHP_FLASH_FLAG_V2_PD_CS1_EN) { + pdval |= BIT(SAF_PWRDN_CTRL_CS1_PD_EN_POS); + } + if (fcfg->flags & MCHP_FLASH_FLAG_V2_PD_CS1_EC_WK_EN) { + pdval |= BIT(SAF_PWRDN_CTRL_CS1_PD_EN_POS); + } + } + + regs->SAF_PWRDN_CTRL = (regs->SAF_PWRDN_CTRL & ~msk) | pdval; +} + +/* Configure SAF per chip select QMSPI clock dividers. + * SAF HW implements two QMSP clock divider registers per chip select: + * Each divider register is composed of two 16-bit fields: + * b[15:0] = QMSPI clock divider for SPI read + * b[31:16] = QMSPI clock divider for all other SPI commands + */ +static int saf_flash_freq_cfg(struct mchp_espi_saf * const regs, uint8_t cs, + const struct espi_saf_flash_cfg *fcfg) +{ + uint32_t fmhz, fdiv, saf_qclk; + + if (cs == 0) { + saf_qclk = regs->SAF_CLKDIV_CS0; + } else { + saf_qclk = regs->SAF_CLKDIV_CS1; + } + + fmhz = fcfg->rd_freq_mhz; + if (fmhz) { + fdiv = 0u; + if (qmspi_freq_div_from_mhz(fmhz, &fdiv)) { + LOG_ERR("%s SAF CLKDIV CS0 bad freq MHz %u", + __func__, fmhz); + return -EIO; + } + if (fdiv) { + saf_qclk = (saf_qclk & ~SAF_CLKDIV_CS_MSK0) | + (fdiv & SAF_CLKDIV_CS_MSK0); + } + } + + fmhz = fcfg->freq_mhz; + if (fmhz) { + fdiv = 0u; + if (qmspi_freq_div_from_mhz(fmhz, &fdiv)) { + LOG_ERR("%s SAF CLKDIV CS1 bad freq MHz %u", + __func__, fmhz); + return -EIO; + } + if (fdiv) { + saf_qclk &= ~(SAF_CLKDIV_CS_MSK0 << 16); + saf_qclk |= (fdiv & SAF_CLKDIV_CS_MSK0) << 16; + } + } + + if (cs == 0) { + regs->SAF_CLKDIV_CS0 = saf_qclk; + } else { + regs->SAF_CLKDIV_CS1 = saf_qclk; + } + + return 0; +} + +/* + * Program flash device specific SAF and QMSPI registers. + * + * CS0 OpA @ 0x4c or CS1 OpA @ 0x5C + * CS0 OpB @ 0x50 or CS1 OpB @ 0x60 + * CS0 OpC @ 0x54 or CS1 OpC @ 0x64 + * Poll 2 Mask @ 0x1a4 + * Continuous Prefix @ 0x1b0 + * CS0: QMSPI descriptors 0-5 or CS1 QMSPI descriptors 6-11 + * CS0 Descrs @ 0x58 or CS1 Descrs @ 0x68 + * SAF CS0 QMSPI frequency dividers (read/all other) commands + * SAF CS1 QMSPI frequency dividers (read/all other) commands + */ +static int saf_flash_cfg(const struct device *dev, + const struct espi_saf_flash_cfg *fcfg, uint8_t cs) +{ + uint32_t d, did; + const struct espi_saf_xec_config * const xcfg = dev->config; + struct mchp_espi_saf * const regs = xcfg->saf_base; + struct qmspi_regs * const qregs = xcfg->qmspi_base; + + LOG_DBG("%s cs=%u", __func__, cs); + + regs->SAF_CS_OP[cs].OPA = fcfg->opa; + regs->SAF_CS_OP[cs].OPB = fcfg->opb; + regs->SAF_CS_OP[cs].OPC = fcfg->opc; + regs->SAF_CS_OP[cs].OP_DESCR = (uint32_t)fcfg->cs_cfg_descr_ids; + + did = MCHP_SAF_QMSPI_CS0_START_DESCR; + if (cs != 0) { + did = MCHP_SAF_QMSPI_CS1_START_DESCR; + } + + for (size_t i = 0; i < MCHP_SAF_QMSPI_NUM_FLASH_DESCR; i++) { + d = fcfg->descr[i] & ~(MCHP_QMSPI_C_NEXT_DESCR_MASK); + d |= (((did + 1) << MCHP_QMSPI_C_NEXT_DESCR_POS) & + MCHP_QMSPI_C_NEXT_DESCR_MASK); + qregs->DESCR[did++] = d; + } + + mchp_saf_poll2_mask_wr(regs, cs, fcfg->poll2_mask); + mchp_saf_cm_prefix_wr(regs, cs, fcfg->cont_prefix); + saf_flash_misc_cfg(regs, cs, fcfg); + saf_flash_pd_cfg(regs, cs, fcfg); + + return saf_flash_freq_cfg(regs, cs, fcfg); +} + +static const uint32_t tag_map_dflt[MCHP_ESPI_SAF_TAGMAP_MAX] = { + MCHP_SAF_TAG_MAP0_DFLT, MCHP_SAF_TAG_MAP1_DFLT, MCHP_SAF_TAG_MAP2_DFLT +}; + +static void saf_tagmap_init(struct mchp_espi_saf * const regs, + const struct espi_saf_cfg *cfg) +{ + const struct espi_saf_hw_cfg *hwcfg = &cfg->hwcfg; + + for (int i = 0; i < MCHP_ESPI_SAF_TAGMAP_MAX; i++) { + if (hwcfg->tag_map[i] & MCHP_SAF_HW_CFG_TAGMAP_USE) { + regs->SAF_TAG_MAP[i] = hwcfg->tag_map[i]; + } else { + regs->SAF_TAG_MAP[i] = tag_map_dflt[i]; + } + } + + LOG_DBG("SAF TAG0 %x", regs->SAF_TAG_MAP[0]); + LOG_DBG("SAF TAG1 %x", regs->SAF_TAG_MAP[1]); + LOG_DBG("SAF TAG2 %x", regs->SAF_TAG_MAP[2]); +} + +#define SAF_QSPI_LDMA_CTRL \ + (MCHP_QMSPI_LDC_EN | MCHP_QMSPI_LDC_RS_EN | \ + MCHP_QMSPI_LDC_ASZ_4) + +static void saf_qmspi_ldma_cfg(const struct espi_saf_xec_config * const xcfg) +{ + struct qmspi_regs * const qregs = xcfg->qmspi_base; + uint32_t qmode = qregs->MODE; + uint32_t n, temp, chan; + + qregs->MODE = qmode & ~(MCHP_QMSPI_M_ACTIVATE); + + for (n = 0u; n < MCHP_QMSPI_MAX_DESCR; n++) { + temp = qregs->DESCR[n]; + if (temp & MCHP_QMSPI_C_TX_MASK) { + chan = (temp & MCHP_QMSPI_C_TX_DMA_MASK) >> MCHP_QMSPI_C_TX_DMA_POS; + if (chan) { /* zero is disabled */ + chan--; /* register array index starts at 0 */ + qregs->LDMA_TX_DESCR_BM |= BIT(n); + qregs->LDTX[chan].CTRL = SAF_QSPI_LDMA_CTRL; + } + } + if (temp & MCHP_QMSPI_C_RX_EN) { + chan = (temp & MCHP_QMSPI_C_RX_DMA_MASK) >> MCHP_QMSPI_C_RX_DMA_POS; + if (chan) { + chan--; + qregs->LDMA_RX_DESCR_BM |= BIT(n); + qregs->LDRX[chan].CTRL = SAF_QSPI_LDMA_CTRL; + } + } + } + + qregs->MODE = qmode; +} + +/* + * Configure SAF and QMSPI for SAF operation based upon the + * number and characteristics of local SPI flash devices. + * NOTE: SAF is configured but not activated. SAF should be + * activated only when eSPI master sends Flash Channel enable + * message with MAF/SAF select flag. + */ +static int espi_saf_xec_configuration(const struct device *dev, + const struct espi_saf_cfg *cfg) +{ + int ret = 0; + uint32_t totalsz = 0; + uint32_t u = 0; + + LOG_DBG("%s", __func__); + + if ((dev == NULL) || (cfg == NULL)) { + return -EINVAL; + } + + const struct espi_saf_xec_config * const xcfg = dev->config; + struct mchp_espi_saf * const regs = xcfg->saf_base; + struct mchp_espi_saf_comm * const comm_regs = xcfg->saf_comm_base; + const struct espi_saf_hw_cfg *hwcfg = &cfg->hwcfg; + const struct espi_saf_flash_cfg *fcfg = cfg->flash_cfgs; + + if ((fcfg == NULL) || (cfg->nflash_devices == 0U) || + (cfg->nflash_devices > MCHP_SAF_MAX_FLASH_DEVICES)) { + return -EINVAL; + } + + if (regs->SAF_FL_CFG_MISC & MCHP_SAF_FL_CFG_MISC_SAF_EN) { + return -EAGAIN; + } + + saf_qmspi_init(xcfg, cfg); + + regs->SAF_CS0_CFG_P2M = 0; + regs->SAF_CS1_CFG_P2M = 0; + + regs->SAF_FL_CFG_GEN_DESCR = MCHP_SAF_FL_CFG_GEN_DESCR_STD; + + /* global flash power down activity counter and interval time */ + regs->SAF_AC_RELOAD = hwcfg->flash_pd_timeout; + regs->SAF_FL_PWR_TMOUT = hwcfg->flash_pd_min_interval; + + /* flash device connected to CS0 required */ + totalsz = fcfg->flashsz; + regs->SAF_FL_CFG_THRH = totalsz; + ret = saf_flash_cfg(dev, fcfg, 0); + if (ret) { + return ret; + } + + /* optional second flash device connected to CS1 */ + if (cfg->nflash_devices > 1) { + fcfg++; + totalsz += fcfg->flashsz; + } + /* Program CS1 configuration (same as CS0 if only one device) */ + ret = saf_flash_cfg(dev, fcfg, 1); + if (ret) { + return ret; + } + + if (totalsz == 0) { + return -EAGAIN; + } + + regs->SAF_FL_CFG_SIZE_LIM = totalsz - 1; + + LOG_DBG("SAF_FL_CFG_THRH = %x SAF_FL_CFG_SIZE_LIM = %x", + regs->SAF_FL_CFG_THRH, regs->SAF_FL_CFG_SIZE_LIM); + + saf_tagmap_init(regs, cfg); + + saf_protection_regions_init(regs); + + saf_dnx_bypass_init(regs); + + saf_flash_timing_init(regs, xcfg); + + ret = saf_init_erase_block_size(dev, cfg); + if (ret != 0) { + LOG_ERR("SAF Config bad flash erase config"); + return ret; + } + + /* Default or expedited prefetch? */ + u = MCHP_SAF_FL_CFG_MISC_PFOE_DFLT; + if (cfg->hwcfg.flags & MCHP_SAF_HW_CFG_FLAG_PFEXP) { + u = MCHP_SAF_FL_CFG_MISC_PFOE_EXP; + } + + regs->SAF_FL_CFG_MISC = + (regs->SAF_FL_CFG_MISC & ~(MCHP_SAF_FL_CFG_MISC_PFOE_MASK)) | u; + + /* enable prefetch ? */ + if (cfg->hwcfg.flags & MCHP_SAF_HW_CFG_FLAG_PFEN) { + comm_regs->SAF_COMM_MODE |= MCHP_SAF_COMM_MODE_PF_EN; + } else { + comm_regs->SAF_COMM_MODE &= ~(MCHP_SAF_COMM_MODE_PF_EN); + } + + LOG_DBG("%s SAF_FL_CFG_MISC: %x", __func__, regs->SAF_FL_CFG_MISC); + LOG_DBG("%s Aft MCHP_SAF_COMM_MODE_REG: %x", __func__, + comm_regs->SAF_COMM_MODE); + + saf_qmspi_ldma_cfg(xcfg); + + return 0; +} + +static int espi_saf_xec_set_pr(const struct device *dev, + const struct espi_saf_protection *pr) +{ + if ((dev == NULL) || (pr == NULL)) { + return -EINVAL; + } + + if (pr->nregions >= MCHP_ESPI_SAF_PR_MAX) { + return -EINVAL; + } + + const struct espi_saf_xec_config * const xcfg = dev->config; + struct mchp_espi_saf * const regs = xcfg->saf_base; + + if (regs->SAF_FL_CFG_MISC & MCHP_SAF_FL_CFG_MISC_SAF_EN) { + return -EAGAIN; + } + + const struct espi_saf_pr *preg = pr->pregions; + size_t n = pr->nregions; + + while (n--) { + uint8_t regnum = preg->pr_num; + + if (regnum >= MCHP_ESPI_SAF_PR_MAX) { + return -EINVAL; + } + + /* NOTE: If previously locked writes have no effect */ + if (preg->flags & MCHP_SAF_PR_FLAG_ENABLE) { + regs->SAF_PROT_RG[regnum].START = preg->start >> 12U; + regs->SAF_PROT_RG[regnum].LIMIT = + (preg->start + preg->size - 1U) >> 12U; + regs->SAF_PROT_RG[regnum].WEBM = preg->master_bm_we; + regs->SAF_PROT_RG[regnum].RDBM = preg->master_bm_rd; + } else { + regs->SAF_PROT_RG[regnum].START = 0x7FFFFU; + regs->SAF_PROT_RG[regnum].LIMIT = 0U; + regs->SAF_PROT_RG[regnum].WEBM = 0U; + regs->SAF_PROT_RG[regnum].RDBM = 0U; + } + + if (preg->flags & MCHP_SAF_PR_FLAG_LOCK) { + regs->SAF_PROT_LOCK |= (1UL << regnum); + } + + preg++; + } + + return 0; +} + +static bool espi_saf_xec_channel_ready(const struct device *dev) +{ + const struct espi_saf_xec_config * const xcfg = dev->config; + struct mchp_espi_saf * const regs = xcfg->saf_base; + + if (regs->SAF_FL_CFG_MISC & MCHP_SAF_FL_CFG_MISC_SAF_EN) { + return true; + } + + return false; +} + +/* + * MCHP SAF hardware supports a range of flash block erase + * sizes from 1KB to 128KB. The eSPI Host specification requires + * 4KB must be supported. The MCHP SAF QMSPI HW interface only + * supported three erase sizes. Most SPI flash devices chosen for + * SAF support 4KB, 32KB, and 64KB. + * Get flash erase sizes driver has configured from eSPI capabilities + * registers. We assume driver flash tables have opcodes to match + * capabilities configuration. + * Check requested erase size is supported. + */ +struct erase_size_encoding { + uint8_t hwbitpos; + uint8_t encoding; +}; + +static const struct erase_size_encoding ersz_enc[] = { + { MCHP_ESPI_SERASE_SZ_4K_BITPOS, 0 }, + { MCHP_ESPI_SERASE_SZ_32K_BITPOS, 1 }, + { MCHP_ESPI_SERASE_SZ_64K_BITPOS, 2 } +}; + +#define SAF_ERASE_ENCODING_MAX_ENTRY \ + (sizeof(ersz_enc) / sizeof(struct erase_size_encoding)) + +static uint32_t get_erase_size_encoding(const struct device *dev, uint32_t erase_size) +{ + const struct espi_saf_xec_config * const xcfg = dev->config; + struct espi_iom_regs * const espi_iom = xcfg->iom_base; + uint8_t supsz = espi_iom->SAFEBS; + + LOG_DBG("%s\n", __func__); + for (int i = 0; i < SAF_ERASE_ENCODING_MAX_ENTRY; i++) { + uint32_t sz = MCHP_ESPI_SERASE_SZ(ersz_enc[i].hwbitpos); + + if ((sz == erase_size) && + (supsz & (1 << ersz_enc[i].hwbitpos))) { + return ersz_enc[i].encoding; + } + } + + return 0xffffffffU; +} + +static int check_ecp_access_size(uint32_t reqlen) +{ + if ((reqlen < MCHP_SAF_ECP_CMD_RW_LEN_MIN) || + (reqlen > MCHP_SAF_ECP_CMD_RW_LEN_MAX)) { + return -EAGAIN; + } + + return 0; +} + +/* + * EC access to SAF atttached flash array + * Allowed commands: + * MCHP_SAF_ECP_CMD_READ(0x0), MCHP_SAF_ECP_CMD_WRITE(0x01), + * MCHP_SAF_ECP_CMD_ERASE(0x02), MCHP_SAF_ECP_CMD_RPMC_OP1_CS0(0x03), + * MCHP_SAF_ECP_CMD_RPMC_OP2_CS0(0x04), MCHP_SAF_ECP_CMD_RPMC_OP1_CS1(0x83), + * MCHP_SAF_ECP_CMD_RPMC_OP2_CS1(0x84) + */ +static int saf_ecp_access(const struct device *dev, + struct espi_saf_packet *pckt, uint8_t cmd) +{ + uint32_t scmd, err_mask, n; + int rc, counter; + struct espi_saf_xec_data *xdat = dev->data; + const struct espi_saf_xec_config * const xcfg = dev->config; + struct mchp_espi_saf * const regs = xcfg->saf_base; + const struct espi_xec_irq_info *safirq = &xcfg->irq_info_list[0]; + + counter = 0; + err_mask = MCHP_SAF_ECP_STS_ERR_MASK; + + LOG_DBG("%s", __func__); + + if (!(regs->SAF_FL_CFG_MISC & MCHP_SAF_FL_CFG_MISC_SAF_EN)) { + LOG_ERR("SAF is disabled"); + return -EIO; + } + + n = regs->SAF_ECP_BUSY; + if (n & (MCHP_SAF_ECP_EC0_BUSY | MCHP_SAF_ECP_EC1_BUSY)) { + LOG_ERR("SAF EC Portal is busy: 0x%08x", n); + return -EBUSY; + } + + switch (cmd) { + case MCHP_SAF_ECP_CMD_READ: + case MCHP_SAF_ECP_CMD_WRITE: + rc = check_ecp_access_size(pckt->len); + if (rc) { + LOG_ERR("SAF EC Portal size out of bounds"); + return rc; + } + + if (cmd == MCHP_SAF_ECP_CMD_WRITE) { + memcpy(slave_mem, pckt->buf, pckt->len); + } + + n = pckt->len; + break; + case MCHP_SAF_ECP_CMD_ERASE: + n = get_erase_size_encoding(dev, pckt->len); + if (n == UINT32_MAX) { + LOG_ERR("SAF EC Portal unsupported erase size"); + return -EAGAIN; + } + break; + case MCHP_SAF_ECP_CMD_RPMC_OP1_CS0: + case MCHP_SAF_ECP_CMD_RPMC_OP2_CS0: + rc = check_ecp_access_size(pckt->len); + if (rc) { + LOG_ERR("SAF EC Portal RPMC size out of bounds"); + return rc; + } + if (!(regs->SAF_CFG_CS0_OPD & SAF_CFG_CS_OPC_RPMC_OP2_MSK)) { + LOG_ERR("SAF CS0 RPMC opcode not configured"); + return -EIO; + } + n = pckt->len; + break; + case MCHP_SAF_ECP_CMD_RPMC_OP1_CS1: + case MCHP_SAF_ECP_CMD_RPMC_OP2_CS1: + rc = check_ecp_access_size(pckt->len); + if (rc) { + LOG_ERR("SAF EC Portal RPMC size out of bounds"); + return rc; + } + if (!(regs->SAF_CFG_CS1_OPD & SAF_CFG_CS_OPC_RPMC_OP2_MSK)) { + LOG_ERR("SAF CS1 RPMC opcode not configured"); + return -EIO; + } + n = pckt->len; + break; + default: + LOG_ERR("SAF EC Portal bad cmd"); + return -EAGAIN; + } + + LOG_DBG("%s params val done", __func__); + + regs->SAF_ECP_INTEN = 0; + regs->SAF_ECP_STATUS = MCHP_SAF_ECP_STS_MASK; + mchp_xec_ecia_girq_src_clr(safirq->gid, safirq->gpos); + + regs->SAF_ECP_INTEN = BIT(MCHP_SAF_ECP_INTEN_DONE_POS); + + regs->SAF_ECP_FLAR = pckt->flash_addr; + regs->SAF_ECP_BFAR = (uint32_t)&slave_mem[0]; + + scmd = MCHP_SAF_ECP_CMD_PUT_FLASH_NP | + ((uint32_t)cmd << MCHP_SAF_ECP_CMD_CTYPE_POS) | + ((n << MCHP_SAF_ECP_CMD_LEN_POS) & MCHP_SAF_ECP_CMD_LEN_MASK); + + LOG_DBG("%s ECP_FLAR=0x%x", __func__, regs->SAF_ECP_FLAR); + LOG_DBG("%s ECP_BFAR=0x%x", __func__, regs->SAF_ECP_BFAR); + LOG_DBG("%s ECP_CMD=0x%x", __func__, scmd); + + regs->SAF_ECP_CMD = scmd; + regs->SAF_ECP_START = MCHP_SAF_ECP_START; + + rc = k_sem_take(&xdat->ecp_lock, K_MSEC(MAX_SAF_FLASH_TIMEOUT_MS)); + if (rc == -EAGAIN) { + LOG_ERR("%s timeout", __func__); + return -ETIMEDOUT; + } + + LOG_DBG("%s wake on semaphore", __func__); + + n = regs->SAF_ECP_STATUS; + /* clear hardware status and check for errors */ + if (n & err_mask) { + regs->SAF_ECP_STATUS = n; + LOG_ERR("%s error %x", __func__, n); + return -EIO; + } + + if (cmd == MCHP_SAF_ECP_CMD_READ) { + memcpy(pckt->buf, slave_mem, pckt->len); + } + + return rc; +} + +/* Flash read using SAF EC Portal */ +static int saf_xec_flash_read(const struct device *dev, + struct espi_saf_packet *pckt) +{ + LOG_DBG("%s", __func__); + return saf_ecp_access(dev, pckt, MCHP_SAF_ECP_CMD_READ); +} + +/* Flash write using SAF EC Portal */ +static int saf_xec_flash_write(const struct device *dev, + struct espi_saf_packet *pckt) +{ + return saf_ecp_access(dev, pckt, MCHP_SAF_ECP_CMD_WRITE); +} + +/* Flash erase using SAF EC Portal */ +static int saf_xec_flash_erase(const struct device *dev, + struct espi_saf_packet *pckt) +{ + return saf_ecp_access(dev, pckt, MCHP_SAF_ECP_CMD_ERASE); +} + +static int espi_saf_xec_manage_callback(const struct device *dev, + struct espi_callback *callback, + bool set) +{ + struct espi_saf_xec_data *data = dev->data; + + return espi_manage_callback(&data->callbacks, callback, set); +} + +static int espi_saf_xec_activate(const struct device *dev) +{ + if (dev == NULL) { + return -EINVAL; + } + + const struct espi_saf_xec_config * const xcfg = dev->config; + struct mchp_espi_saf * const regs = xcfg->saf_base; + const struct espi_xec_irq_info *safirq = &xcfg->irq_info_list[1]; + + regs->SAF_ESPI_MON_STATUS = MCHP_SAF_ESPI_MON_STS_IEN_MSK; + mchp_xec_ecia_girq_src_clr(safirq->gid, safirq->gpos); + + regs->SAF_FL_CFG_MISC |= MCHP_SAF_FL_CFG_MISC_SAF_EN; + regs->SAF_ESPI_MON_INTEN = (BIT(MCHP_SAF_ESPI_MON_STS_IEN_TMOUT_POS) | + BIT(MCHP_SAF_ESPI_MON_STS_IEN_OOR_POS) | + BIT(MCHP_SAF_ESPI_MON_STS_IEN_AV_POS) | + BIT(MCHP_SAF_ESPI_MON_STS_IEN_BND_4K_POS) | + BIT(MCHP_SAF_ESPI_MON_STS_IEN_ERSZ_POS)); + + k_busy_wait(1000); /* TODO FIXME get estimate of time interval */ + + return 0; +} + +static void espi_saf_done_isr(const struct device *dev) +{ + const struct espi_saf_xec_config * const xcfg = dev->config; + struct espi_saf_xec_data *data = dev->data; + struct mchp_espi_saf * const regs = xcfg->saf_base; + const struct espi_xec_irq_info *safirq = &xcfg->irq_info_list[0]; + uint32_t ecp_status = regs->SAF_ECP_STATUS; + struct espi_event evt = { .evt_type = ESPI_BUS_SAF_NOTIFICATION, + .evt_details = BIT(0), + .evt_data = ecp_status }; + + regs->SAF_ECP_INTEN = 0u; + regs->SAF_ECP_STATUS = BIT(MCHP_SAF_ECP_STS_DONE_POS); + mchp_xec_ecia_girq_src_clr(safirq->gid, safirq->gpos); + + data->hwstatus = ecp_status; + + LOG_DBG("SAF Done ISR: status=0x%x", ecp_status); + + espi_send_callbacks(&data->callbacks, dev, evt); + + k_sem_give(&data->ecp_lock); +} + +static void espi_saf_err_isr(const struct device *dev) +{ + const struct espi_saf_xec_config * const xcfg = dev->config; + struct espi_saf_xec_data *data = dev->data; + struct mchp_espi_saf * const regs = xcfg->saf_base; + const struct espi_xec_irq_info *safirq = &xcfg->irq_info_list[1]; + uint32_t mon_status = regs->SAF_ESPI_MON_STATUS; + struct espi_event evt = { .evt_type = ESPI_BUS_PERIPHERAL_NOTIFICATION, + .evt_details = BIT(7), + .evt_data = mon_status }; + + regs->SAF_ESPI_MON_STATUS = mon_status; + mchp_xec_ecia_girq_src_clr(safirq->gid, safirq->gpos); + + data->hwstatus = mon_status; + espi_send_callbacks(&data->callbacks, dev, evt); +} + +static const struct espi_saf_driver_api espi_saf_xec_driver_api = { + .config = espi_saf_xec_configuration, + .set_protection_regions = espi_saf_xec_set_pr, + .activate = espi_saf_xec_activate, + .get_channel_status = espi_saf_xec_channel_ready, + .flash_read = saf_xec_flash_read, + .flash_write = saf_xec_flash_write, + .flash_erase = saf_xec_flash_erase, + .manage_callback = espi_saf_xec_manage_callback, +}; + +static int espi_saf_xec_init(const struct device *dev) +{ + const struct espi_saf_xec_config * const xcfg = dev->config; + struct espi_saf_xec_data * const data = dev->data; + struct espi_iom_regs * const espi_iom = xcfg->iom_base; + + /* ungate SAF clocks by disabling PCR sleep enable */ + z_mchp_xec_pcr_periph_sleep(xcfg->pcr_idx, xcfg->pcr_pos, 0); + + /* Configure the channels and its capabilities based on build config */ + espi_iom->CAP0 |= MCHP_ESPI_GBL_CAP0_FC_SUPP; + espi_iom->CAPFC &= ~(MCHP_ESPI_FC_CAP_SHARE_MASK); + espi_iom->CAPFC |= MCHP_ESPI_FC_CAP_SHARE_MAF_SAF; + + xcfg->irq_config_func(); + + k_sem_init(&data->ecp_lock, 0, 1); + + return 0; +} + + +/* n = node-id, p = property, i = index */ +#define XEC_SAF_IRQ_INFO(n, p, i) \ + { \ + .gid = MCHP_XEC_ECIA_GIRQ(DT_PROP_BY_IDX(n, p, i)), \ + .gpos = MCHP_XEC_ECIA_GIRQ_POS(DT_PROP_BY_IDX(n, p, i)), \ + .anid = MCHP_XEC_ECIA_NVIC_AGGR(DT_PROP_BY_IDX(n, p, i)), \ + .dnid = MCHP_XEC_ECIA_NVIC_DIRECT(DT_PROP_BY_IDX(n, p, i)), \ + }, + +#define ESPI_SAF_XEC_DEVICE(n) \ + \ + static struct espi_saf_xec_data espisaf_xec_data_##n; \ + \ + static void espi_saf_xec_connect_irqs_##n(void); \ + \ + static const struct espi_xec_irq_info espi_saf_xec_irq_info_##n[] = { \ + DT_INST_FOREACH_PROP_ELEM(n, girqs, XEC_SAF_IRQ_INFO) \ + }; \ + \ + static const struct espi_saf_xec_config espisaf_xec_config_##n = { \ + .saf_base = (struct mchp_espi_saf * const)( \ + DT_INST_REG_ADDR_BY_IDX(n, 0)), \ + .qmspi_base = (struct qmspi_regs * const)( \ + DT_INST_REG_ADDR_BY_IDX(n, 1)), \ + .saf_comm_base = (struct mchp_espi_saf_comm * const)( \ + DT_INST_REG_ADDR_BY_IDX(n, 2)), \ + .iom_base = (struct espi_iom_regs * const)( \ + DT_REG_ADDR_BY_NAME(DT_INST_PARENT(n), io)), \ + .poll_timeout = DT_INST_PROP_OR(n, poll_timeout, \ + MCHP_SAF_FLASH_POLL_TIMEOUT), \ + .consec_rd_timeout = DT_INST_PROP_OR( \ + n, consec_rd_timeout, MCHP_SAF_FLASH_CONSEC_READ_TIMEOUT), \ + .sus_chk_delay = DT_INST_PROP_OR(n, sus_chk_delay, \ + MCHP_SAF_FLASH_SUS_CHK_DELAY), \ + .sus_rsm_interval = DT_INST_PROP_OR(n, sus_rsm_interval, \ + MCHP_SAF_FLASH_SUS_RSM_INTERVAL), \ + .poll_interval = DT_INST_PROP_OR(n, poll_interval, \ + MCHP_SAF_FLASH_POLL_INTERVAL), \ + .pcr_idx = DT_INST_PROP_BY_IDX(n, pcrs, 0), \ + .pcr_pos = DT_INST_PROP_BY_IDX(n, pcrs, 1), \ + .irq_config_func = espi_saf_xec_connect_irqs_##n, \ + .irq_info_size = ARRAY_SIZE(espi_saf_xec_irq_info_##n), \ + .irq_info_list = espi_saf_xec_irq_info_##n, \ + }; \ + DEVICE_DT_INST_DEFINE(0, &espi_saf_xec_init, NULL, \ + &espisaf_xec_data_##n, \ + &espisaf_xec_config_##n, POST_KERNEL, \ + CONFIG_ESPI_SAF_INIT_PRIORITY, \ + &espi_saf_xec_driver_api); \ + \ + static void espi_saf_xec_connect_irqs_##n(void) \ + { \ + uint8_t girq, gpos; \ + \ + /* SAF Done */ \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 0, irq), \ + DT_INST_IRQ_BY_IDX(n, 0, priority), \ + espi_saf_done_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQ_BY_IDX(n, 0, irq)); \ + \ + girq = MCHP_XEC_ECIA_GIRQ(DT_INST_PROP_BY_IDX(n, girqs, 0)); \ + gpos = MCHP_XEC_ECIA_GIRQ_POS(DT_INST_PROP_BY_IDX(n, girqs, 0)); \ + mchp_xec_ecia_girq_src_en(girq, gpos); \ + \ + /* SAF Error */ \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 1, irq), \ + DT_INST_IRQ_BY_IDX(n, 1, priority), \ + espi_saf_err_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQ_BY_IDX(n, 1, irq)); \ + \ + girq = MCHP_XEC_ECIA_GIRQ(DT_INST_PROP_BY_IDX(n, girqs, 1)); \ + gpos = MCHP_XEC_ECIA_GIRQ_POS(DT_INST_PROP_BY_IDX(n, girqs, 1)); \ + mchp_xec_ecia_girq_src_en(girq, gpos); \ + } + +DT_INST_FOREACH_STATUS_OKAY(ESPI_SAF_XEC_DEVICE) diff --git a/dts/arm/microchip/mec172xnsz.dtsi b/dts/arm/microchip/mec172xnsz.dtsi index 80fc9f17df0e75..226e1ff8559297 100644 --- a/dts/arm/microchip/mec172xnsz.dtsi +++ b/dts/arm/microchip/mec172xnsz.dtsi @@ -798,12 +798,17 @@ }; espi0: espi@400f3400 { compatible = "microchip,xec-espi-v2"; + /* reg tuple contains one 32-bit address cell and one + * 32-bit length(size) cell. + */ + #address-cells = <1>; + #size-cells = <1>; reg = < 0x400f3400 0x400 0x400f3800 0x400 0x400f9c00 0x400>; reg-names = "io", "mem", "vw"; interrupts = <103 3>, <104 3>, <105 3>, <106 3>, - <107 3>, <108 3>, <109 3>, <110 3>, + <107 3>, <108 3>, <109 3>, <110 2>, <156 3>; interrupt-names = "pc", "bm1", "bm2", "ltr", "oob_up", "oob_dn", "fc", "rst", "vw_chan_en"; @@ -817,10 +822,21 @@ MCHP_XEC_ECIA(19, 7, 11, 110) MCHP_XEC_ECIA(19, 8, 11, 156) >; pcrs = <2 19>; - #address-cells = <1>; - #size-cells = <0>; status = "disabled"; + espi_saf0: espi_saf@40008000 { + compatible = "microchip,xec-espi-saf-v2"; + reg = <0x40008000 0x400>, <0x40070000 0x400>, + <0x40071000 0x400>; + reg-names = "safbr", "safqspi", "safcomm"; + interrupts = <166 3>, <167 3>; + interrupt-names = "done", "err"; + girqs = < MCHP_XEC_ECIA(19, 9, 11, 166) >, + < MCHP_XEC_ECIA(19, 10, 11, 167) >; + pcrs = <2 27>; + status = "disabled"; + }; + mbox0: mbox@400f0000 { compatible = "microchip,xec-espi-host-dev"; reg = <0x400f0000 0x200>; diff --git a/dts/bindings/espi/microchip,xec-espi-saf-v2.yaml b/dts/bindings/espi/microchip,xec-espi-saf-v2.yaml new file mode 100644 index 00000000000000..367b6bac74ce6b --- /dev/null +++ b/dts/bindings/espi/microchip,xec-espi-saf-v2.yaml @@ -0,0 +1,64 @@ +# Copyright (c) 2019 Intel Corporation +# Copyright (c) 2022 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: Microchip ESPI SAF version 2 controller + +compatible: "microchip,xec-espi-saf-v2" + +include: espi-controller.yaml + +properties: + reg: + description: mmio register space + required: true + + girqs: + type: array + required: true + description: Array of encoded interrupt information + + pcrs: + type: array + required: true + description: Array of eSPI PCR register index and bit position + + poll-timeout: + type: int + description: poll flash busy timeout in 32KHz periods + required: false + + poll-interval: + type: int + description: interval between flash busy poll in 20 ns units + required: false + + consec-rd-timeout: + type: int + description: timeout after last read to resume supended operations in 20 ns units + required: false + + sus-chk-delay: + type: int + description: hold off poll after suspend in 20 ns units + required: false + + sus-rsm-interval: + type: int + description: force suspended erase or program to resume in 32KHz periods + required: false + + "#girq-cells": + type: int + const: 1 + + "#pcr-cells": + type: int + const: 2 + +girq-cells: + - girqinfo + +pcr-cells: + - regidx + - bitpos diff --git a/include/zephyr/drivers/espi.h b/include/zephyr/drivers/espi.h index 70d5b8a10ca0ec..b2c09a1316a15b 100644 --- a/include/zephyr/drivers/espi.h +++ b/include/zephyr/drivers/espi.h @@ -117,6 +117,7 @@ enum espi_bus_event { ESPI_BUS_EVENT_VWIRE_RECEIVED = BIT(2), ESPI_BUS_EVENT_OOB_RECEIVED = BIT(3), ESPI_BUS_PERIPHERAL_NOTIFICATION = BIT(4), + ESPI_BUS_SAF_NOTIFICATION = BIT(5), }; /** diff --git a/soc/arm/microchip_mec/mec172x/reg/mec172x_espi_saf.h b/soc/arm/microchip_mec/mec172x/reg/mec172x_espi_saf.h index b69e868ddcc841..006010bdb0f1f3 100644 --- a/soc/arm/microchip_mec/mec172x/reg/mec172x_espi_saf.h +++ b/soc/arm/microchip_mec/mec172x/reg/mec172x_espi_saf.h @@ -36,30 +36,40 @@ /* Register bit definitions */ /* SAF EC Portal Command register */ -#define MCHP_SAF_ECP_CMD_OFS 0x18u -#define MCHP_SAF_ECP_CMD_MASK 0xff00ffffu -#define MCHP_SAF_ECP_CMD_PUT_POS 0 -#define MCHP_SAF_ECP_CMD_PUT_MASK 0xffu -#define MCHP_SAF_ECP_CMD_PUT_FLASH_NP 0x0au -#define MCHP_SAF_ECP_CMD_CTYPE_POS 8 -#define MCHP_SAF_ECP_CMD_CTYPE_READ0 0x00u -#define MCHP_SAF_ECP_CMD_CTYPE_WRITE0 0x01u -#define MCHP_SAF_ECP_CMD_CTYPE_ERASE0 0x02u -#define MCHP_SAF_ECP_CMD_CTYPE_MAX0 0x03u -#define MCHP_SAF_ECP_CMD_CTYPE_MASK 0xff00ul -#define MCHP_SAF_ECP_CMD_CTYPE_READ 0x0000ul -#define MCHP_SAF_ECP_CMD_CTYPE_WRITE 0x0100ul -#define MCHP_SAF_ECP_CMD_CTYPE_ERASE 0x0200ul -#define MCHP_SAF_ECP_CMD_LEN_POS 24 -#define MCHP_SAF_ECP_CMD_LEN_MASK0 0xffu -#define MCHP_SAF_ECP_CMD_LEN_MASK 0xff000000ul +#define MCHP_SAF_ECP_CMD_OFS 0x18u +#define MCHP_SAF_ECP_CMD_MASK 0xff00ffffu +#define MCHP_SAF_ECP_CMD_PUT_POS 0 +#define MCHP_SAF_ECP_CMD_PUT_MASK 0xffu +#define MCHP_SAF_ECP_CMD_PUT_FLASH_NP 0x0au +#define MCHP_SAF_ECP_CMD_CTYPE_POS 8 +#define MCHP_SAF_ECP_CMD_CTYPE_MSK0 0xffu +#define MCHP_SAF_ECP_CMD_CTYPE_MASK 0xff00u +#define MCHP_SAF_ECP_CMD_CTYPE_READ 0x0000u +#define MCHP_SAF_ECP_CMD_CTYPE_WRITE 0x0100u +#define MCHP_SAF_ECP_CMD_CTYPE_ERASE 0x0200u +#define MCHP_SAF_ECP_CMD_CTYPE_RPMC_OP1_CS0 0x0300u +#define MCHP_SAF_ECP_CMD_CTYPE_RPMC_OP2_CS0 0x0400u +#define MCHP_SAF_ECP_CMD_CTYPE_RPMC_OP1_CS1 0x8300u +#define MCHP_SAF_ECP_CMD_CTYPE_RPMC_OP2_CS1 0x8400u +#define MCHP_SAF_ECP_CMD_LEN_POS 24 +#define MCHP_SAF_ECP_CMD_LEN_MASK0 0xffu +#define MCHP_SAF_ECP_CMD_LEN_MASK 0xff000000ul /* Read/Write request size (1 <= reqlen <= 64) bytes */ -#define MCHP_SAF_ECP_CMD_RW_LEN_MIN 1u -#define MCHP_SAF_ECP_CMD_RW_LEN_MAX 64u +#define MCHP_SAF_ECP_CMD_RW_LEN_MIN 1u +#define MCHP_SAF_ECP_CMD_RW_LEN_MAX 64u /* Only three erase sizes are supported encoded as */ -#define MCHP_SAF_ECP_CMD_ERASE_4K 0u -#define MCHP_SAF_ECP_CMD_ERASE_32K BIT(24) -#define MCHP_SAF_ECP_CMD_ERASE_64K BIT(25) +#define MCHP_SAF_ECP_CMD_ERASE_4K 0u +#define MCHP_SAF_ECP_CMD_ERASE_32K BIT(24) +#define MCHP_SAF_ECP_CMD_ERASE_64K BIT(25) + +/* Zero based command values */ +#define MCHP_SAF_ECP_CMD_READ 0x00u +#define MCHP_SAF_ECP_CMD_WRITE 0x01u +#define MCHP_SAF_ECP_CMD_ERASE 0x02u +#define MCHP_SAF_ECP_CMD_RPMC_OP1_CS0 0x03u +#define MCHP_SAF_ECP_CMD_RPMC_OP2_CS0 0x04u +#define MCHP_SAF_ECP_CMD_RPMC_OP1_CS1 0x83u +#define MCHP_SAF_ECP_CMD_RPMC_OP2_CS1 0x84u /* SAF EC Portal Flash Address register */ #define MCHP_SAF_ECP_FLAR_OFS 0x1cu @@ -68,6 +78,7 @@ /* SAF EC Portal Start register */ #define MCHP_SAF_ECP_START_OFS 0x20u #define MCHP_SAF_ECP_START_MASK 0x01u +#define MCHP_SAF_ECP_START_POS 0 #define MCHP_SAF_ECP_START BIT(0) /* SAF EC Portal Buffer Address register */ @@ -78,6 +89,15 @@ #define MCHP_SAF_ECP_STS_OFS 0x28u #define MCHP_SAF_ECP_STS_MASK 0x1ffu #define MCHP_SAF_ECP_STS_ERR_MASK 0x1fcu +#define MCHP_SAF_ECP_STS_DONE_POS 0 +#define MCHP_SAF_ECP_STS_DONE_TST_POS 1 +#define MCHP_SAF_ECP_STS_TMOUT_POS 2 +#define MCHP_SAF_ECP_STS_OOR_POS 3 +#define MCHP_SAF_ECP_STS_AV_POS 4 +#define MCHP_SAF_ECP_STS_BND_4K_POS 5 +#define MCHP_SAF_ECP_STS_ERSZ_POS 6 +#define MCHP_SAF_ECP_STS_ST_OVFL_POS 7 +#define MCHP_SAF_ECP_STS_BAD_REQ_POS 8 #define MCHP_SAF_ECP_STS_DONE BIT(0) #define MCHP_SAF_ECP_STS_DONE_TST BIT(1) #define MCHP_SAF_ECP_STS_TMOUT BIT(2) @@ -91,6 +111,7 @@ /* SAF EC Portal Interrupt Enable register */ #define MCHP_SAF_ECP_INTEN_OFS 0x2cu #define MCHP_SAF_ECP_INTEN_MASK 0x01u +#define MCHP_SAF_ECP_INTEN_DONE_POS 0 #define MCHP_SAF_ECP_INTEN_DONE BIT(0) /* SAF Flash Configuration Size Limit register */ @@ -102,40 +123,46 @@ #define MCHP_SAF_FL_CFG_THRH_MASK 0xffffffffu /* SAF Flash Configuration Miscellaneous register */ -#define MCHP_SAF_FL_CFG_MISC_OFS 0x38u -#define MCHP_SAF_FL_CFG_MISC_MASK 0x000030f3u -#define MCHP_SAF_FL_CFG_MISC_PFOE_MASK 0x03u -#define MCHP_SAF_FL_CFG_MISC_PFOE_DFLT 0x00u -#define MCHP_SAF_FL_CFG_MISC_PFOE_EXP 0x03u -#define MCHP_SAF_FL_CFG_MISC_CS0_4BM BIT(4) -#define MCHP_SAF_FL_CFG_MISC_CS1_4BM BIT(5) -#define MCHP_SAF_FL_CFG_MISC_CS0_CPE BIT(6) -#define MCHP_SAF_FL_CFG_MISC_CS1_CPE BIT(7) -#define MCHP_SAF_FL_CFG_MISC_SAF_EN BIT(12) -#define MCHP_SAF_FL_CFG_MISC_SAF_LOCK BIT(13) - -/* SAF eSPI Monitor Status register */ -#define MCHP_SAF_ESPI_MON_STATUS_OFS 0x3cu -#define MCHP_SAF_ESPI_MON_STATUS_MASK 0x1fu -#define MCHP_SAF_ESPI_MON_STS_TMOUT BIT(0) -#define MCHP_SAF_ESPI_MON_STS_OOR BIT(1) -#define MCHP_SAF_ESPI_MON_STS_AV BIT(2) -#define MCHP_SAF_ESPI_MON_STS_BND_4K BIT(3) -#define MCHP_SAF_ESPI_MON_STS_ERSZ BIT(4) - -/* SAF eSPI Monitor Interrupt Enable register */ -#define MCHP_SAF_ESPI_MON_INTEN_OFS 0x40u -#define MCHP_SAF_ESPI_MON_INTEN_MASK 0x1fu -#define MCHP_SAF_ESPI_MON_INTEN_TMOUT BIT(0) -#define MCHP_SAF_ESPI_MON_INTEN_OOR BIT(1) -#define MCHP_SAF_ESPI_MON_INTEN_AV BIT(2) -#define MCHP_SAF_ESPI_MON_INTEN_BND_4K BIT(3) -#define MCHP_SAF_ESPI_MON_INTEN_ERSZ BIT(4) +#define MCHP_SAF_FL_CFG_MISC_OFS 0x38u +#define MCHP_SAF_FL_CFG_MISC_MASK 0x000030f3u +#define MCHP_SAF_FL_CFG_MISC_PFOE_MASK 0x3u +#define MCHP_SAF_FL_CFG_MISC_PFOE_DFLT 0u +#define MCHP_SAF_FL_CFG_MISC_PFOE_EXP 0x3u +#define MCHP_SAF_FL_CFG_MISC_CS0_4BM_POS 4 +#define MCHP_SAF_FL_CFG_MISC_CS1_4BM_POS 5 +#define MCHP_SAF_FL_CFG_MISC_CS0_CPE_POS 6 +#define MCHP_SAF_FL_CFG_MISC_CS1_CPE_POS 7 +#define MCHP_SAF_FL_CFG_MISC_SAF_EN_POS 12 +#define MCHP_SAF_FL_CFG_MISC_SAF_LOCK_POS 13 +#define MCHP_SAF_FL_CFG_MISC_CS0_4BM BIT(4) +#define MCHP_SAF_FL_CFG_MISC_CS1_4BM BIT(5) +#define MCHP_SAF_FL_CFG_MISC_CS0_CPE BIT(6) +#define MCHP_SAF_FL_CFG_MISC_CS1_CPE BIT(7) +#define MCHP_SAF_FL_CFG_MISC_SAF_EN BIT(12) +#define MCHP_SAF_FL_CFG_MISC_SAF_LOCK BIT(13) + +/* SAF eSPI Monitor Status and Interrupt enable registers */ +#define MCHP_SAF_ESPI_MON_STATUS_OFS 0x3cu +#define MCHP_SAF_ESPI_MON_INTEN_OFS 0x40u +#define MCHP_SAF_ESPI_MON_STS_IEN_MSK 0x1fu +#define MCHP_SAF_ESPI_MON_STS_IEN_TMOUT_POS 0 +#define MCHP_SAF_ESPI_MON_STS_IEN_OOR_POS 1 +#define MCHP_SAF_ESPI_MON_STS_IEN_AV_POS 2 +#define MCHP_SAF_ESPI_MON_STS_IEN_BND_4K_POS 3 +#define MCHP_SAF_ESPI_MON_STS_IEN_ERSZ_POS 4 +#define MCHP_SAF_ESPI_MON_STS_IEN_TMOUT BIT(0) +#define MCHP_SAF_ESPI_MON_STS_IEN_OOR BIT(1) +#define MCHP_SAF_ESPI_MON_STS_IEN_AV BIT(2) +#define MCHP_SAF_ESPI_MON_STS_IEN_BND_4K BIT(3) +#define MCHP_SAF_ESPI_MON_STS_IEN_ERSZ BIT(4) /* SAF EC Portal Busy register */ #define MCHP_SAF_ECP_BUSY_OFS 0x44u #define MCHP_SAF_ECP_BUSY_MASK 0x01u -#define MCHP_SAF_ECP_BUSY BIT(0) +#define MCHP_SAF_ECP_EC0_BUSY_POS 0 +#define MCHP_SAF_ECP_EC1_BUSY_POS 1 +#define MCHP_SAF_ECP_EC0_BUSY BIT(0) +#define MCHP_SAF_ECP_EC1_BUSY BIT(1) /* SAF CS0/CS1 Opcode A registers */ #define MCHP_SAF_CS0_OPA_OFS 0x4cu @@ -444,7 +471,64 @@ /* SAF DnX Protection Bypass register */ #define MCHP_SAF_DNX_PROT_BYP_OFS 0x1b4u -#define MCHP_SAF_DNX_PROT_BYP_MASK 0xffffffffu +#define MCHP_SAF_DNX_PROT_BYP_MASK 0x1110ffffu +#define MCHP_SAF_DNX_PB_TAG_POS(n) ((uint32_t)(n) & 0xfu) +#define MCHP_SAF_DNX_PB_TAG(n) BIT(((n) & 0xfu)) +#define MCHP_SAF_DNX_DS_RO_POS 20 +#define MCHP_SAF_DNX_DS_RO BIT(20) +#define MCHP_SAF_DNX_DM_POS 24 +#define MCHP_SAF_DNX_DM BIT(24) +#define MCHP_SAF_DNX_LK_POS 28 +#define MCHP_SAF_DNX_LK BIT(28) + +/* SAF Activity Count Reload Valud register */ +#define MCHP_SAF_AC_RELOAD_OFS 0x1b8u +#define MCHP_SAF_AC_RELOAD_REG_MSK 0xffffu + +/* SAF Power Down Control register */ +#define SAF_PWRDN_CTRL_OFS 0x1bcu +#define SAF_PWRDN_CTRL_REG_MSK 0x0fu +#define SAF_PWRDN_CTRL_CS0_PD_EN_POS 0 +#define SAF_PWRDN_CTRL_CS1_PD_EN_POS 1 +#define SAF_PWRDN_CTRL_CS0_WPA_EN_POS 2 +#define SAF_PWRDN_CTRL_CS1_WPA_EN_POS 3 + +/* SAF Memory Power Status register (RO) */ +#define SAF_MEM_PWR_STS_OFS 0x1c0u +#define SAF_MEM_PWR_STS_REG_MSK 0x03u + +/* SAF Config CS0 and CS1 Opcode registers */ +#define SAF_CFG_CS0_OPC_OFS 0x1c4u +#define SAF_CFG_CS1_OPC_OFS 0x1c8u +#define SAF_CFG_CS_OPC_REG_MSK 0x00ffffffu +#define SAF_CFG_CS_OPC_ENTER_PD_POS 0 +#define SAF_CFG_CS_OPC_ENTER_PD_MSK0 0xffu +#define SAF_CFG_CS_OPC_ENTER_PD_MSK 0xffu +#define SAF_CFG_CS_OPC_EXIT_PD_POS 8 +#define SAF_CFG_CS_OPC_EXIT_PD_MSK0 0xffu +#define SAF_CFG_CS_OPC_EXIT_PD_MSK 0xff00u +#define SAF_CFG_CS_OPC_RPMC_OP2_POS 16 +#define SAF_CFG_CS_OPC_RPMC_OP2_MSK0 0xffu +#define SAF_CFG_CS_OPC_RPMC_OP2_MSK 0xff0000u + + +/* SAF Flash Power Down/Up Timerout register */ +#define SAF_FL_PWR_TMOUT_OFS 0x1ccu +#define SAF_FL_PWR_TMOUT_REG_MSK 0xffffu + +/* SAF Clock Divider CS0 and CS1 registers */ +#define SAF_CLKDIV_CS0_OFS 0x200u +#define SAF_CLKDIV_CS1_OFS 0x204u +#define SAF_CLKDIV_CS_REG_MSK 0xffffffffu +#define SAF_CLKDIV_CS_READ_POS 0 +#define SAF_CLKDIV_CS_REST_POS 16 +#define SAF_CLKDIV_CS_MSK0 0xffffu + +/* SAF RPMC OP2 eSPI, EC0, and EC1 Result Address register */ +#define SAF_RPMC_OP2_ESPI_RES_OFS 0x208u +#define SAF_RPMC_OP2_EC0_RES_OFS 0x20cu +#define SAF_RPMC_OP2_EC1_RES_OFS 0x210u +#define SAF_RPMC_OP2_RES_REG_MSK 0xffffffffu /* SAF Communication Mode */ #define MCHP_SAF_COMM_MODE_MASK 0x01u @@ -496,36 +580,48 @@ struct mchp_espi_saf_pr { /** @brief eSPI SAF configuration and control registers at 0x40008000 */ struct mchp_espi_saf { uint32_t RSVD1[6]; - volatile uint32_t SAF_ECP_CMD; - volatile uint32_t SAF_ECP_FLAR; - volatile uint32_t SAF_ECP_START; - volatile uint32_t SAF_ECP_BFAR; - volatile uint32_t SAF_ECP_STATUS; - volatile uint32_t SAF_ECP_INTEN; - volatile uint32_t SAF_FL_CFG_SIZE_LIM; - volatile uint32_t SAF_FL_CFG_THRH; - volatile uint32_t SAF_FL_CFG_MISC; - volatile uint32_t SAF_ESPI_MON_STATUS; - volatile uint32_t SAF_ESPI_MON_INTEN; - volatile uint32_t SAF_ECP_BUSY; + volatile uint32_t SAF_ECP_CMD; /* 0x18 */ + volatile uint32_t SAF_ECP_FLAR; /* 0x1c */ + volatile uint32_t SAF_ECP_START; /* 0x20 */ + volatile uint32_t SAF_ECP_BFAR; /* 0x24 */ + volatile uint32_t SAF_ECP_STATUS; /* 0x28 */ + volatile uint32_t SAF_ECP_INTEN; /* 0x2c */ + volatile uint32_t SAF_FL_CFG_SIZE_LIM; /* 0x30 */ + volatile uint32_t SAF_FL_CFG_THRH; /* 0x34 */ + volatile uint32_t SAF_FL_CFG_MISC; /* 0x38 */ + volatile uint32_t SAF_ESPI_MON_STATUS; /* 0x3c */ + volatile uint32_t SAF_ESPI_MON_INTEN; /* 0x40 */ + volatile uint32_t SAF_ECP_BUSY; /* 0x44 */ uint32_t RSVD2[1]; - struct mchp_espi_saf_op SAF_CS_OP[2]; - volatile uint32_t SAF_FL_CFG_GEN_DESCR; - volatile uint32_t SAF_PROT_LOCK; - volatile uint32_t SAF_PROT_DIRTY; - volatile uint32_t SAF_TAG_MAP[3]; - struct mchp_espi_saf_pr SAF_PROT_RG[17]; - volatile uint32_t SAF_POLL_TMOUT; - volatile uint32_t SAF_POLL_INTRVL; - volatile uint32_t SAF_SUS_RSM_INTRVL; - volatile uint32_t SAF_CONSEC_RD_TMOUT; - volatile uint16_t SAF_CS0_CFG_P2M; - volatile uint16_t SAF_CS1_CFG_P2M; - volatile uint32_t SAF_FL_CFG_SPM; - volatile uint32_t SAF_SUS_CHK_DLY; - volatile uint16_t SAF_CS0_CM_PRF; - volatile uint16_t SAF_CS1_CM_PRF; - volatile uint32_t SAF_DNX_PROT_BYP; + struct mchp_espi_saf_op SAF_CS_OP[2]; /* 0x4c - 0x6b */ + volatile uint32_t SAF_FL_CFG_GEN_DESCR; /* 0x6c */ + volatile uint32_t SAF_PROT_LOCK; /* 0x70 */ + volatile uint32_t SAF_PROT_DIRTY; /* 0x74 */ + volatile uint32_t SAF_TAG_MAP[3]; /* 0x78 - 0x83 */ + struct mchp_espi_saf_pr SAF_PROT_RG[17]; /* 0x84 - 0x193 */ + volatile uint32_t SAF_POLL_TMOUT; /* 0x194 */ + volatile uint32_t SAF_POLL_INTRVL; /* 0x198 */ + volatile uint32_t SAF_SUS_RSM_INTRVL; /* 0x19c */ + volatile uint32_t SAF_CONSEC_RD_TMOUT; /* 0x1a0 */ + volatile uint16_t SAF_CS0_CFG_P2M; /* 0x1a4 */ + volatile uint16_t SAF_CS1_CFG_P2M; /* 0x1a6 */ + volatile uint32_t SAF_FL_CFG_SPM; /* 0x1a8 */ + volatile uint32_t SAF_SUS_CHK_DLY; /* 0x1ac */ + volatile uint16_t SAF_CS0_CM_PRF; /* 0x1b0 */ + volatile uint16_t SAF_CS1_CM_PRF; /* 0x1b2 */ + volatile uint32_t SAF_DNX_PROT_BYP; /* 0x1b4 */ + volatile uint32_t SAF_AC_RELOAD; /* 0x1b8 */ + volatile uint32_t SAF_PWRDN_CTRL; /* 0x1bc */ + volatile uint32_t SAF_MEM_PWR_STS; /* 0x1c0 */ + volatile uint32_t SAF_CFG_CS0_OPD; /* 0x1c4 */ + volatile uint32_t SAF_CFG_CS1_OPD; /* 0x1c8 */ + volatile uint32_t SAF_FL_PWR_TMOUT; /* 0x1cc */ + uint32_t RSVD[12]; + volatile uint32_t SAF_CLKDIV_CS0; /* 0x200 */ + volatile uint32_t SAF_CLKDIV_CS1; /* 0x204 */ + volatile uint32_t SAF_RPMC_OP2_ESPI_RES; /* 0x208 */ + volatile uint32_t SAF_RPMC_OP2_EC0_RES; /* 0x20c */ + volatile uint32_t SAF_RPMC_OP2_EC1_RES; /* 0x210 */ }; struct mchp_espi_saf_comm { /* @ 0x40071000 */ diff --git a/soc/arm/microchip_mec/mec172x/reg/mec172x_qspi.h b/soc/arm/microchip_mec/mec172x/reg/mec172x_qspi.h index 496c0f5238c861..fa04a2da01411a 100644 --- a/soc/arm/microchip_mec/mec172x/reg/mec172x_qspi.h +++ b/soc/arm/microchip_mec/mec172x/reg/mec172x_qspi.h @@ -188,6 +188,9 @@ #define MCHP_QMSPI_C_TX_DMA_1B SHLU32(1u, MCHP_QMSPI_C_TX_DMA_POS) #define MCHP_QMSPI_C_TX_DMA_2B SHLU32(2u, MCHP_QMSPI_C_TX_DMA_POS) #define MCHP_QMSPI_C_TX_DMA_4B SHLU32(3u, MCHP_QMSPI_C_TX_DMA_POS) +#define MCHP_QMSPI_C_TX_LDMA_CH0 SHLU32(1u, MCHP_QMSPI_C_TX_DMA_POS) +#define MCHP_QMSPI_C_TX_LDMA_CH1 SHLU32(2u, MCHP_QMSPI_C_TX_DMA_POS) +#define MCHP_QMSPI_C_TX_LDMA_CH2 SHLU32(3u, MCHP_QMSPI_C_TX_DMA_POS) #define MCHP_QMSPI_C_RX_POS 6u #define MCHP_QMSPI_C_RX_DIS 0u #define MCHP_QMSPI_C_RX_EN BIT(MCHP_QMSPI_C_RX_POS) @@ -197,6 +200,9 @@ #define MCHP_QMSPI_C_RX_DMA_1B SHLU32(1u, MCHP_QMSPI_C_RX_DMA_POS) #define MCHP_QMSPI_C_RX_DMA_2B SHLU32(2u, MCHP_QMSPI_C_RX_DMA_POS) #define MCHP_QMSPI_C_RX_DMA_4B SHLU32(3u, MCHP_QMSPI_C_RX_DMA_POS) +#define MCHP_QMSPI_C_RX_LDMA_CH0 SHLU32(1u, MCHP_QMSPI_C_RX_DMA_POS) +#define MCHP_QMSPI_C_RX_LDMA_CH1 SHLU32(2u, MCHP_QMSPI_C_RX_DMA_POS) +#define MCHP_QMSPI_C_RX_lDMA_CH2 SHLU32(3u, MCHP_QMSPI_C_RX_DMA_POS) #define MCHP_QMSPI_C_CLOSE_POS 9u #define MCHP_QMSPI_C_NO_CLOSE 0u diff --git a/soc/arm/microchip_mec/mec172x/soc.h b/soc/arm/microchip_mec/mec172x/soc.h index 3087dc4ac5a980..3bf4f533fdb775 100644 --- a/soc/arm/microchip_mec/mec172x/soc.h +++ b/soc/arm/microchip_mec/mec172x/soc.h @@ -284,6 +284,9 @@ typedef enum { #include "../common/soc_espi_channels.h" #include "../common/soc_i2c.h" +/* MEC172x SAF V2 */ +#include "soc_espi_saf_v2.h" + #endif #endif diff --git a/soc/arm/microchip_mec/mec172x/soc_espi_saf_v2.h b/soc/arm/microchip_mec/mec172x/soc_espi_saf_v2.h new file mode 100644 index 00000000000000..3e00e3592d0e14 --- /dev/null +++ b/soc/arm/microchip_mec/mec172x/soc_espi_saf_v2.h @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2020 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file Header containing definitions for MCHP eSPI SAF + */ + +#ifndef _SOC_ESPI_SAF_H_ +#define _SOC_ESPI_SAF_H_ + +#include +#include + +#define MCHP_SAF_MAX_FLASH_DEVICES 2U + +/* + * SAF hardware state machine timings + * poll timeout is in 32KHz clock periods + * poll interval is in AHB clock(48MHz) units. + * suspend resume interval is in 32KHz clock periods. + * consecutive read timeout is in AHB clock periods. + * suspend check delay is in AHB clock(48MHz) periods. + */ +#define MCHP_SAF_FLASH_POLL_TIMEOUT 0x28000u +#define MCHP_SAF_FLASH_POLL_INTERVAL 0u +#define MCHP_SAF_FLASH_SUS_RSM_INTERVAL 8u +#define MCHP_SAF_FLASH_CONSEC_READ_TIMEOUT 2u +#define MCHP_SAF_FLASH_SUS_CHK_DELAY 0u + +/* Default SAF Map of eSPI TAG numbers to master numbers */ +#define MCHP_SAF_TAG_MAP0_DFLT 0x23221100u +#define MCHP_SAF_TAG_MAP1_DFLT 0x77677767u +#define MCHP_SAF_TAG_MAP2_DFLT 0x00000005u + +/* + * Default QMSPI clock divider and chip select timing. + * QMSPI master clock is either 96 or 48 MHz depending upon + * Boot-ROM OTP configuration. + */ +#define MCHP_SAF_QMSPI_CLK_DIV 4u + +/* SAF V2 implements dynamically changing the QMSPI clock + * divider for SPI read vs all other SPI commands. + */ +#define MCHP_SAF_CS_CLK_DIV(read, other) \ + (((uint32_t)(read) & 0xffffu) | (((uint32_t)(other) & 0xffffu) << 16)) + +#define MCHP_SAF_CS0_CLK_DIV MCHP_SAF_CS_CLK_DIV(4, 4) +#define MCHP_SAF_CS1_CLK_DIV MCHP_SAF_CS_CLK_DIV(4, 4) + +#define MCHP_SAF_QMSPI_CS_TIMING 0x03000101u + +/* SAF QMSPI programming */ + +#define MCHP_SAF_QMSPI_NUM_FLASH_DESCR 6u +#define MCHP_SAF_QMSPI_CS0_START_DESCR 0u +#define MCHP_SAF_QMSPI_CS1_START_DESCR \ + (MCHP_SAF_QMSPI_CS0_START_DESCR + MCHP_SAF_QMSPI_NUM_FLASH_DESCR) + +/* SAF engine requires start indices of descriptor chains */ +#define MCHP_SAF_CM_EXIT_START_DESCR 12u +#define MCHP_SAF_CM_EXIT_LAST_DESCR 13u +#define MCHP_SAF_POLL_STS_START_DESCR 14u +#define MCHP_SAF_POLL_STS_END_DESCR 15u +#define MCHP_SAF_NUM_GENERIC_DESCR 4u + +/* QMSPI descriptors 12-15 for all SPI flash devices */ + +/* QMSPI descriptors 12-13 are exit continuous mode */ +#define MCHP_SAF_EXIT_CM_DESCR12 \ + (MCHP_QMSPI_C_IFM_4X | MCHP_QMSPI_C_TX_ONES | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_NO_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | \ + MCHP_QMSPI_C_NEXT_DESCR(13) | \ + MCHP_QMSPI_C_XFR_NUNITS(1)) + +#define MCHP_SAF_EXIT_CM_DESCR13 \ + (MCHP_QMSPI_C_IFM_4X | MCHP_QMSPI_C_TX_DIS | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_EN | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | \ + MCHP_QMSPI_C_NEXT_DESCR(0) | \ + MCHP_QMSPI_C_XFR_NUNITS(9) | \ + MCHP_QMSPI_C_DESCR_LAST) + +#define MCHP_SAF_EXIT_CM_DUAL_DESCR12 \ + (MCHP_QMSPI_C_IFM_2X | MCHP_QMSPI_C_TX_ONES | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_NO_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | \ + MCHP_QMSPI_C_NEXT_DESCR(13) | \ + MCHP_QMSPI_C_XFR_NUNITS(1)) + +#define MCHP_SAF_EXIT_CM_DUAL_DESCR13 \ + (MCHP_QMSPI_C_IFM_2X | MCHP_QMSPI_C_TX_DIS | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_EN | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | \ + MCHP_QMSPI_C_NEXT_DESCR(0) | \ + MCHP_QMSPI_C_XFR_NUNITS(5) | \ + MCHP_QMSPI_C_DESCR_LAST) + +/* + * QMSPI descriptors 14-15 are poll 16-bit flash status + * Transmit one byte opcode at 1X (no DMA). + * Receive two bytes at 1X (no DMA). + */ +#define MCHP_SAF_POLL_DESCR14 \ + (MCHP_QMSPI_C_IFM_1X | MCHP_QMSPI_C_TX_DATA | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_NO_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | \ + MCHP_QMSPI_C_NEXT_DESCR(15) | \ + MCHP_QMSPI_C_XFR_NUNITS(1)) + +#define MCHP_SAF_POLL_DESCR15 \ + (MCHP_QMSPI_C_IFM_1X | MCHP_QMSPI_C_TX_DIS | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_EN | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | \ + MCHP_QMSPI_C_NEXT_DESCR(0) | \ + MCHP_QMSPI_C_XFR_NUNITS(2) | \ + MCHP_QMSPI_C_DESCR_LAST) + + +/* SAF Pre-fetch optimization mode */ +#define MCHP_SAF_PREFETCH_MODE MCHP_SAF_FL_CFG_MISC_PFOE_DFLT + +#define MCHP_SAF_CFG_MISC_PREFETCH_EXPEDITED 0x03U + +/* + * SAF Opcode 32-bit register value. + * Each byte contain a SPI flash 8-bit opcode. + * NOTE1: opcode value of 0 = flash does not support this operation + * NOTE2: + * SAF Opcode A + * op0 = SPI flash write-enable opcode + * op1 = SPI flash program/erase suspend opcode + * op2 = SPI flash program/erase resume opcode + * op3 = SPI flash read STATUS1 opcode + * SAF Opcode B + * op0 = SPI flash erase 4KB sector opcode + * op1 = SPI flash erase 32KB sector opcode + * op2 = SPI flash erase 64KB sector opcode + * op3 = SPI flash page program opcode + * SAF Opcode C + * op0 = SPI flash read 1-4-4 continuous mode opcode + * op1 = SPI flash op0 mode byte value for non-continuous mode + * op2 = SPI flash op0 mode byte value for continuous mode + * op3 = SPI flash read STATUS2 opcode + */ +#define MCHP_SAF_OPCODE_REG_VAL(op0, op1, op2, op3) \ + (((uint32_t)(op0)&0xffU) | (((uint32_t)(op1)&0xffU) << 8) | \ + (((uint32_t)(op2)&0xffU) << 16) | (((uint32_t)(op3)&0xffU) << 24)) + +/* + * SAF Flash Config CS0/CS1 QMSPI descriptor indices register value + * e = First QMSPI descriptor index for enter continuous mode chain + * r = First QMSPI descriptor index for continuous mode read chain + * s = Index of QMSPI descriptor in continuous mode read chain that + * contains the data length field. + */ +#define MCHP_SAF_CS_CFG_DESCR_IDX_REG_VAL(e, r, s) \ + (((uint32_t)(e)&0xfU) | (((uint32_t)(r)&0xfU) << 8) | \ + (((uint32_t)(s)&0xfU) << 12)) + +/* W25Q128 SPI flash device connected size in bytes */ +#define MCHP_W25Q128_SIZE (16U * 1024U * 1024U) + +/* + * Six QMSPI descriptors describe SPI flash opcode protocols. + * Example: W25Q128 + */ +/* Continuous mode read: transmit-quad 24-bit address and mode byte */ +#define MCHP_W25Q128_CM_RD_D0 \ + (MCHP_QMSPI_C_IFM_4X | MCHP_QMSPI_C_TX_DATA | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_NO_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | MCHP_QMSPI_C_XFR_NUNITS(4)) + +/* Continuous mode read: transmit-quad 4 dummy clocks with I/O tri-stated */ +#define MCHP_W25Q128_CM_RD_D1 \ + (MCHP_QMSPI_C_IFM_4X | MCHP_QMSPI_C_TX_DIS | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_NO_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | MCHP_QMSPI_C_XFR_NUNITS(2)) + +/* Continuous mode read: read N bytes */ +#define MCHP_W25Q128_CM_RD_D2 \ + (MCHP_QMSPI_C_IFM_4X | MCHP_QMSPI_C_TX_DIS | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_EN | \ + MCHP_QMSPI_C_RX_LDMA_CH0 | MCHP_QMSPI_C_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | \ + MCHP_QMSPI_C_XFR_NUNITS(0) | MCHP_QMSPI_C_DESCR_LAST) + +/* Continuous Mode: 24-bit address plus mode byte */ +#define MCHP_W25Q128_CM_RD_DUAL_D0 \ + (MCHP_QMSPI_C_IFM_2X | MCHP_QMSPI_C_TX_DATA | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_NO_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | MCHP_QMSPI_C_XFR_NUNITS(4)) + +/* Continuous mode read: read N bytes */ +#define MCHP_W25Q128_CM_RD_DUAL_D1 \ + (MCHP_QMSPI_C_IFM_2X | MCHP_QMSPI_C_TX_DIS | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_EN | \ + MCHP_QMSPI_C_RX_LDMA_CH0 | MCHP_QMSPI_C_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | \ + MCHP_QMSPI_C_XFR_NUNITS(0) | MCHP_QMSPI_C_DESCR_LAST) + +/* Continuous mode Dual D2. Not used */ +#define MCHP_W25Q128_CM_RD_DUAL_D2 0 + +/* Enter Continuous mode: transmit-single CM quad read opcode */ +#define MCHP_W25Q128_ENTER_CM_D0 \ + (MCHP_QMSPI_C_IFM_1X | MCHP_QMSPI_C_TX_DATA | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_NO_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | MCHP_QMSPI_C_XFR_NUNITS(1)) + +/* Enter Continuous mode: transmit-quad 24-bit address and mode byte */ +#define MCHP_W25Q128_ENTER_CM_D1 \ + (MCHP_QMSPI_C_IFM_4X | MCHP_QMSPI_C_TX_DATA | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_NO_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | MCHP_QMSPI_C_XFR_NUNITS(4)) + +/* Enter Continuous mode: read-quad 3 bytes */ +#define MCHP_W25Q128_ENTER_CM_D2 \ + (MCHP_QMSPI_C_IFM_4X | MCHP_QMSPI_C_TX_DIS | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | \ + MCHP_QMSPI_C_XFR_NUNITS(3) | MCHP_QMSPI_C_DESCR_LAST) + +/* Enter Continuous mode: transmit-single CM dual read opcode */ +#define MCHP_W25Q128_ENTER_CM_DUAL_D0 \ + (MCHP_QMSPI_C_IFM_1X | MCHP_QMSPI_C_TX_DATA | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_NO_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | MCHP_QMSPI_C_XFR_NUNITS(1)) + +/* Enter Continuous mode: transmit-dual 24-bit address and mode byte */ +#define MCHP_W25Q128_ENTER_CM_DUAL_D1 \ + (MCHP_QMSPI_C_IFM_2X | MCHP_QMSPI_C_TX_DATA | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_NO_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | MCHP_QMSPI_C_XFR_NUNITS(4)) + +/* Enter Continuous mode: read-dual 3 bytes */ +#define MCHP_W25Q128_ENTER_CM_DUAL_D2 \ + (MCHP_QMSPI_C_IFM_2X | MCHP_QMSPI_C_TX_DIS | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | \ + MCHP_QMSPI_C_XFR_NUNITS(3) | MCHP_QMSPI_C_DESCR_LAST) + +#define MCHP_W25Q128_OPA MCHP_SAF_OPCODE_REG_VAL(0x06u, 0x75u, 0x7au, 0x05u) +#define MCHP_W25Q128_OPB MCHP_SAF_OPCODE_REG_VAL(0x20u, 0x52u, 0xd8u, 0x02u) +#define MCHP_W25Q128_OPC MCHP_SAF_OPCODE_REG_VAL(0xebu, 0xffu, 0xa5u, 0x35u) +#define MCHP_W25Q128_OPD MCHP_SAF_OPCODE_REG_VAL(0xb9u, 0xabu, 0u, 0u) + +#define MCHP_W25Q128_DUAL_OPC MCHP_SAF_OPCODE_REG_VAL(0xbbu, 0xffu, 0xa5u, 0x35u) + +/* W25Q128 STATUS2 bit[7] == 0 part is NOT in suspend state */ +#define MCHP_W25Q128_POLL2_MASK 0xff7fU + +/* + * SAF Flash Continuous Mode Prefix register value + * b[7:0] = continuous mode prefix opcode + * b[15:8] = continuous mode prefix opcode data + * Some SPI flash devices require a prefix command before + * they will enter continuous mode. + * A zero value means the SPI flash does not require a prefix + * command. + */ +#define MCHP_W25Q128_CONT_MODE_PREFIX_VAL 0u + +/* SAF Flash power down/up activity timeout in 32KHz units */ +#define MCHP_W25Q128_PD_TIMEOUT_32K 0x10u + +/* SAF Flash minimum time between power up and down events in + * 48MHz time units (~20 ns) + */ +#define MCHP_W25Q128_PD_EVENT_INTERVAL 0x4ffu + +#define MCHP_SAF_PD_EVENT_INTERVAL_25US 1279u + + +#define MCHP_W25Q128_FLAGS 0U + + +/* W25Q256 SPI flash device connected size in bytes */ +#define MCHP_W25Q256_SIZE (32U * 1024U * 1024U) + +/* + * Six QMSPI descriptors describe SPI flash opcode protocols. + * W25Q256 device. + */ + +/* Continuous Mode Read: Transmit-quad opcode plus 32-bit address */ +#define MCHP_W25Q256_CM_RD_D0 \ + (MCHP_QMSPI_C_IFM_4X | MCHP_QMSPI_C_TX_DATA | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_NO_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | MCHP_QMSPI_C_XFR_NUNITS(5)) + +#define MCHP_W25Q256_CM_RD_D1 \ + (MCHP_QMSPI_C_IFM_4X | MCHP_QMSPI_C_TX_DIS | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_NO_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | MCHP_QMSPI_C_XFR_NUNITS(2)) + +#define MCHP_W25Q256_CM_RD_D2 \ + (MCHP_QMSPI_C_IFM_4X | MCHP_QMSPI_C_TX_DIS | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_EN | \ + MCHP_QMSPI_C_RX_LDMA_CH0 | MCHP_QMSPI_C_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | MCHP_QMSPI_C_XFR_NUNITS(0) | \ + MCHP_QMSPI_C_DESCR_LAST) + +/* Enter Continuous mode: transmit-single CM quad read opcode */ +#define MCHP_W25Q256_ENTER_CM_D0 \ + (MCHP_QMSPI_C_IFM_1X | MCHP_QMSPI_C_TX_DATA | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_NO_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | MCHP_QMSPI_C_XFR_NUNITS(1)) + +/* Enter Continuous mode: transmit-quad 32-bit address and mode byte */ +#define MCHP_W25Q256_ENTER_CM_D1 \ + (MCHP_QMSPI_C_IFM_4X | MCHP_QMSPI_C_TX_DATA | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_NO_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | MCHP_QMSPI_C_XFR_NUNITS(5)) + +/* Enter Continuous mode: read-quad 3 bytes */ +#define MCHP_W25Q256_ENTER_CM_D2 \ + (MCHP_QMSPI_C_IFM_4X | MCHP_QMSPI_C_TX_DIS | \ + MCHP_QMSPI_C_TX_DMA_DIS | MCHP_QMSPI_C_RX_DIS | \ + MCHP_QMSPI_C_RX_DMA_DIS | MCHP_QMSPI_C_CLOSE | \ + MCHP_QMSPI_C_XFR_UNITS_1 | MCHP_QMSPI_C_XFR_NUNITS(3) | \ + MCHP_QMSPI_C_DESCR_LAST) + +#define MCHP_W25Q256_OPA MCHP_SAF_OPCODE_REG_VAL(0x06U, 0x75U, 0x7aU, 0x05U) +#define MCHP_W25Q256_OPB MCHP_SAF_OPCODE_REG_VAL(0x20U, 0x52U, 0xd8U, 0x02U) +#define MCHP_W25Q256_OPC MCHP_SAF_OPCODE_REG_VAL(0xebU, 0xffU, 0xa5U, 0x35U) +#define MCHP_W25Q256_OPD MCHP_SAF_OPCODE_REG_VAL(0xb9U, 0xabU, 0U, 0U) + +#define MCHP_W25Q256_POLL2_MASK 0xff7fU + +#define MCHP_W25Q256_CONT_MODE_PREFIX_VAL 0U + +#define MCHP_W25Q256_FLAGS 0U + +/* SAF Flash Config CS0 QMSPI descriptor indices */ +#define MCHP_CS0_CFG_DESCR_IDX_REG_VAL \ + MCHP_SAF_CS_CFG_DESCR_IDX_REG_VAL(3U, 0U, 2U) + +#define MCHP_CS0_CFG_DESCR_IDX_REG_VAL_DUAL \ + MCHP_SAF_CS_CFG_DESCR_IDX_REG_VAL(3U, 0U, 1U) + +/* SAF Flash Config CS1 QMSPI descriptor indices */ +#define MCHP_CS1_CFG_DESCR_IDX_REG_VAL \ + MCHP_SAF_CS_CFG_DESCR_IDX_REG_VAL(9U, 6U, 8U) + +#define MCHP_CS1_CFG_DESCR_IDX_REG_VAL_DUAL \ + MCHP_SAF_CS_CFG_DESCR_IDX_REG_VAL(9U, 6U, 7U) + +#define MCHP_SAF_HW_CFG_FLAG_FREQ 0x01U +#define MCHP_SAF_HW_CFG_FLAG_CSTM 0x02U +#define MCHP_SAF_HW_CFG_FLAG_CPHA 0x04U + +/* enable SAF prefetch */ +#define MCHP_SAF_HW_CFG_FLAG_PFEN 0x10U +/* Use expedited prefetch instead of default */ +#define MCHP_SAF_HW_CFG_FLAG_PFEXP 0x20U + +/* + * Override the default tag map value when this bit is set + * in a tag_map[]. + */ +#define MCHP_SAF_HW_CFG_TAGMAP_USE BIT(31) + +#define MCHP_SAF_VER_1 0 +#define MCHP_SAF_VER_2 1 + +struct espi_saf_hw_cfg { + uint8_t version; + uint8_t flags; + uint8_t rsvd1; + uint8_t qmspi_cpha; + uint32_t qmspi_cs_timing; + uint16_t flash_pd_timeout; + uint16_t flash_pd_min_interval; + uint32_t generic_descr[MCHP_SAF_NUM_GENERIC_DESCR]; + uint32_t tag_map[MCHP_ESPI_SAF_TAGMAP_MAX]; +}; + +/* + * SAF local flash configuration. + * Version: 0 = V1, 1 = V2(this version) + * miscellaneous configuration flags + * SPI flash device size in bytes + * SPI opcodes for SAF Opcode A register + * SPI opcodes for SAF Opcode B register + * SPI opcodes for SAF Opcode C register + * SPI opcodes for SAF Opcode D register: power down/up and + * RPMC continuous mode read + * SAF controller Poll2 Mask value specific for this flash device + * SAF continuous mode prefix register value for those flashes requiring + * a prefix byte transmitted before the enter continuous mode command. + * Start QMSPI descriptor numbers. + * Power down timeout count in units of 32 KHz ticks. + * Minimum interval between power down/up commands in 48 MHz units. + * QMSPI descriptors describing SPI opcode transmit and data read. + */ + +/* Flags */ +#define MCHP_FLASH_FLAG_ADDR32 BIT(0) +#define MCHP_FLASH_FLAG_V1_MSK 0xffu +#define MCHP_FLASH_FLAG_V2_MSK 0xff00u +#define MCHP_FLASH_FLAG_V2_PD_CS0_EN BIT(8) +#define MCHP_FLASH_FLAG_V2_PD_CS1_EN BIT(9) +#define MCHP_FLASH_FLAG_V2_PD_CS0_EC_WK_EN BIT(10) +#define MCHP_FLASH_FLAG_V2_PD_CS1_EC_WK_EN BIT(11) + +struct espi_saf_flash_cfg { + uint8_t version; + uint8_t rsvd1; + uint16_t flags; + uint32_t flashsz; + uint8_t rd_freq_mhz; + uint8_t freq_mhz; + uint8_t rsvd2[2]; + uint32_t opa; + uint32_t opb; + uint32_t opc; + uint32_t opd; + uint16_t poll2_mask; + uint16_t cont_prefix; + uint16_t cs_cfg_descr_ids; + uint16_t rsvd3; + uint32_t descr[MCHP_SAF_QMSPI_NUM_FLASH_DESCR]; +}; + + +/* + * 17 flash protection regions + * Each region is described by: + * SPI start address. 20-bits = bits[31:12] of SPI address + * SPI limit address. 20-bits = bits[31:12] of last SPI address + * 8-bit bit map of eSPI master write-erase permission + * 8-bit bit map of eSPI maste read permission + * eSPI master numbers 0 - 7 correspond to bits 0 - 7. + * + * Protection region lock: + * One 32-bit register with bits[16:0] -> protection regions 16:0 + * + * eSPI Host maps threads by a tag number to master numbers. + * Thread numbers are 4-bit + * Master numbers are 3-bit + * Master number Thread numbers Description + * 0 0h, 1h Host PCH HW init + * 1 2h, 3h Host CPU access(HW/BIOS/SMM/SW) + * 2 4h, 5h Host PCH ME + * 3 6h Host PCH LAN + * 4 N/A Not defined/used + * 5 N/A EC Firmware portal access + * 6 9h, Dh Host PCH IE + * 7 N/A Not defined/used + * + * NOTE: eSPI SAF specification allows master 0 (Host PCH HW) full + * access to all protection regions. + * + * SAF TAG Map registers 0 - 2 map eSPI TAG values 0h - Fh to + * the three bit master number. Each 32-bit register contains 3-bit + * fields aligned on nibble boundaries holding the master number + * associated with the eSPI tag (thread) number. + * A master value of 7h in a field indicates a non-existent map entry. + * + * bit map of registers to program + * b[2:0] = TAG Map[2:0] + * b[20:4] = ProtectionRegions[16:0] + * bit map of PR's to lock + * b[20:4] = ProtectionRegions[16:0] + * + */ +#define MCHP_SAF_PR_FLAG_ENABLE 0x01U +#define MCHP_SAF_PR_FLAG_LOCK 0x02U + +#define MCHP_SAF_MSTR_HOST_PCH 0U +#define MCHP_SAF_MSTR_HOST_CPU 1U +#define MCHP_SAF_MSTR_HOST_PCH_ME 2U +#define MCHP_SAF_MSTR_HOST_PCH_LAN 3U +#define MCHP_SAF_MSTR_RSVD4 4U +#define MCHP_SAF_MSTR_EC 5U +#define MCHP_SAF_MSTR_HOST_PCH_IE 6U + +struct espi_saf_pr { + uint32_t start; + uint32_t size; + uint8_t master_bm_we; + uint8_t master_bm_rd; + uint8_t pr_num; + uint8_t flags; /* bit[0]==1 is lock the region */ +}; + +struct espi_saf_protection { + size_t nregions; + const struct espi_saf_pr *pregions; +}; + +#endif /* _SOC_ESPI_SAF_H_ */