drivers: espi: Microchip eSPI add SAF support
Add ESPI SAF features to the Microchip eSPI driver as
a separate file. ESPI SAF depends upon the core eSPI
driver adding the ability to attach the system SPI
flash to the EC eSPI endpoint instead of the host
eSPI controller.
Signed-off-by: Scott Worley <scott.worley@microchip.com>
diff --git a/drivers/espi/CMakeLists.txt b/drivers/espi/CMakeLists.txt
index 601462a..d26e50c 100644
--- a/drivers/espi/CMakeLists.txt
+++ b/drivers/espi/CMakeLists.txt
@@ -3,7 +3,8 @@
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_ESPI_XEC espi_mchp_xec.c)
-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_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)
diff --git a/drivers/espi/Kconfig.xec b/drivers/espi/Kconfig.xec
index e7a7565..debbc92 100644
--- a/drivers/espi/Kconfig.xec
+++ b/drivers/espi/Kconfig.xec
@@ -37,4 +37,19 @@
This tells the driver to which SoC UART to direct the UART traffic
send over eSPI from host.
+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
diff --git a/drivers/espi/espi_saf_mchp_xec.c b/drivers/espi/espi_saf_mchp_xec.c
new file mode 100644
index 0000000..17714e2
--- /dev/null
+++ b/drivers/espi/espi_saf_mchp_xec.c
@@ -0,0 +1,876 @@
+/*
+ * Copyright (c) 2019 Intel Corporation
+ * Copyright (c) 2020 Microchip Technology Inc.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define DT_DRV_COMPAT microchip_xec_espi_saf
+
+#include <kernel.h>
+#include <soc.h>
+#include <errno.h>
+#include <drivers/espi.h>
+#include <drivers/espi_saf.h>
+#include <logging/log.h>
+
+#include "espi_utils.h"
+LOG_MODULE_REGISTER(espi_saf, CONFIG_ESPI_LOG_LEVEL);
+
+/* 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 */
+
+/* 64 bytes @ 24MHz quad is approx. 6 us */
+#define SAF_WAIT_INTERVAL 8
+
+/* After 8 wait intervals yield */
+#define SAF_YIELD_THRESHOLD 64
+
+struct espi_isr {
+ uint32_t girq_bit;
+ void (*the_isr)(const struct device *dev);
+};
+
+/*
+ * 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 {
+ uintptr_t saf_base_addr;
+ uintptr_t qmspi_base_addr;
+ uintptr_t saf_comm_base_addr;
+ uint32_t poll_timeout;
+ uint32_t consec_rd_timeout;
+ uint32_t sus_chk_delay;
+ uint16_t sus_rsm_interval;
+ uint16_t poll_interval;
+};
+
+struct espi_saf_xec_data {
+ sys_slist_t callbacks;
+ struct k_sem ecp_lock;
+ uint32_t hwstatus;
+};
+
+/* convenience defines */
+#define DEV_CFG(dev) ((const struct espi_saf_xec_config *const)(dev)->config)
+#define DEV_DATA(dev) ((struct espi_saf_xec_data *const)(dev)->data)
+
+/* 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(MCHP_SAF_HW_REGS *regs, uint8_t cs,
+ uint32_t val)
+{
+ regs->SAF_CS_OP[cs].OP_DESCR = val;
+}
+
+static inline void mchp_saf_poll2_mask_wr(MCHP_SAF_HW_REGS *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(MCHP_SAF_HW_REGS *regs, uint8_t cs,
+ uint16_t val)
+{
+ if (cs == 0) {
+ regs->SAF_CS0_CM_PRF = val;
+ } else {
+ regs->SAF_CS1_CM_PRF = val;
+ }
+}
+
+/* busy wait or yield until we have SAF interrupt support */
+static int xec_saf_spin_yield(int *counter)
+{
+ *counter = *counter + 1;
+
+ if (*counter > MAX_SAF_FLASH_TIMEOUT) {
+ return -ETIMEDOUT;
+ }
+
+ if (*counter > SAF_YIELD_THRESHOLD) {
+ k_yield();
+ } else {
+ k_busy_wait(SAF_WAIT_INTERVAL);
+ }
+
+ return 0;
+}
+
+/*
+ * 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(MCHP_SAF_HW_REGS *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 uint32_t qmspi_freq_div(uint32_t freqhz)
+{
+ uint32_t fdiv;
+
+ if (freqhz < (MCHP_QMSPI_MIN_FREQ_KHZ * 1000U)) {
+ fdiv = 0U; /* freq divider field -> 256 */
+ } else if (freqhz >= (MCHP_QMSPI_MAX_FREQ_KHZ * 1000U)) {
+ fdiv = 1U;
+ } else {
+ /* truncation produces next higher integer frequency */
+ fdiv = MCHP_QMSPI_INPUT_CLOCK_FREQ_HZ / freqhz;
+ }
+
+ fdiv &= MCHP_QMSPI_M_FDIV_MASK0;
+ fdiv <<= MCHP_QMSPI_M_FDIV_POS;
+
+ return 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, cstim, n;
+ QMSPI_Type *regs = (QMSPI_Type *)xcfg->qmspi_base_addr;
+ const struct espi_saf_hw_cfg *hwcfg = &cfg->hwcfg;
+
+ qmode = regs->MODE;
+ if (!(qmode & MCHP_QMSPI_M_ACTIVATE)) {
+ return -EAGAIN;
+ }
+
+ qmode = regs->MODE & (MCHP_QMSPI_M_FDIV_MASK | MCHP_QMSPI_M_SIG_MASK);
+ cstim = regs->CSTM;
+ regs->MODE = MCHP_QMSPI_M_SRST;
+ regs->STS = MCHP_QMSPI_STS_RW1C_MASK;
+
+ MCHP_GIRQ_ENCLR(MCHP_QMSPI_GIRQ_NUM) = MCHP_QMSPI_GIRQ_VAL;
+ MCHP_GIRQ_SRC(MCHP_QMSPI_GIRQ_NUM) = MCHP_QMSPI_GIRQ_VAL;
+
+ regs->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++) {
+ regs->DESCR[MCHP_SAF_CM_EXIT_START_DESCR + n] =
+ hwcfg->generic_descr[n];
+ }
+
+ regs->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);
+ }
+
+ if (hwcfg->flags & MCHP_SAF_HW_CFG_FLAG_FREQ) {
+ qmode = (qmode & ~(MCHP_QMSPI_M_FDIV_MASK)) |
+ qmspi_freq_div(hwcfg->qmspi_freq_hz);
+ }
+
+ if (hwcfg->flags & MCHP_SAF_HW_CFG_FLAG_CSTM) {
+ cstim = hwcfg->qmspi_cs_timing;
+ }
+
+ regs->MODE = qmode;
+ regs->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(MCHP_SAF_HW_REGS *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(MCHP_SAF_HW_REGS *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 espi_saf_cfg *cfg)
+{
+ 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_CAP_REGS->FC_SERBZ = 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(MCHP_SAF_HW_REGS *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);
+}
+
+/*
+ * 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
+ */
+static void 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 *xcfg = DEV_CFG(dev);
+ MCHP_SAF_HW_REGS *regs = (MCHP_SAF_HW_REGS *)xcfg->saf_base_addr;
+ QMSPI_Type *qregs = (QMSPI_Type *)xcfg->qmspi_base_addr;
+
+ 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);
+}
+
+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(MCHP_SAF_HW_REGS *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]);
+}
+
+/*
+ * 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 *xcfg = DEV_CFG(dev);
+ MCHP_SAF_HW_REGS *regs = (MCHP_SAF_HW_REGS *)xcfg->saf_base_addr;
+ 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;
+
+ /* flash device connected to CS0 required */
+ totalsz = fcfg->flashsz;
+ regs->SAF_FL_CFG_THRH = totalsz;
+ saf_flash_cfg(dev, fcfg, 0);
+
+ /* 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) */
+ saf_flash_cfg(dev, fcfg, 1);
+
+ 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(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) {
+ MCHP_SAF_COMM_MODE_REG |= MCHP_SAF_COMM_MODE_PF_EN;
+ } else {
+ MCHP_SAF_COMM_MODE_REG &= ~(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__,
+ MCHP_SAF_COMM_MODE_REG);
+
+ 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 *xcfg = DEV_CFG(dev);
+ MCHP_SAF_HW_REGS *regs = (MCHP_SAF_HW_REGS *)xcfg->saf_base_addr;
+
+ 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 *cfg = DEV_CFG(dev);
+ MCHP_SAF_HW_REGS *regs = (MCHP_SAF_HW_REGS *)cfg->saf_base_addr;
+
+ 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(uint32_t erase_size)
+{
+ uint8_t supsz = ESPI_CAP_REGS->FC_SERBZ;
+
+ 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 (read/erase/write) to SAF atttached flash array
+ * cmd 0 = read
+ * 1 = write
+ * 2 = erase
+ */
+static int saf_ecp_access(const struct device *dev,
+ struct espi_saf_packet *pckt, uint8_t cmd)
+{
+ uint32_t err_mask, n;
+ int rc, counter;
+ struct espi_saf_xec_data *xdat = DEV_DATA(dev);
+ const struct espi_saf_xec_config *cfg = DEV_CFG(dev);
+ MCHP_SAF_HW_REGS *regs = (MCHP_SAF_HW_REGS *)cfg->saf_base_addr;
+
+ 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;
+ }
+
+ if (regs->SAF_ECP_BUSY & MCHP_SAF_ECP_BUSY) {
+ LOG_ERR("SAF EC Portal is busy");
+ return -EBUSY;
+ }
+
+ if ((cmd == MCHP_SAF_ECP_CMD_CTYPE_READ0) ||
+ (cmd == MCHP_SAF_ECP_CMD_CTYPE_WRITE0)) {
+ 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_CTYPE_WRITE0) {
+ memcpy(slave_mem, pckt->buf, pckt->len);
+ }
+
+ n = pckt->len;
+ } else if (cmd == MCHP_SAF_ECP_CMD_CTYPE_ERASE0) {
+ n = get_erase_size_encoding(pckt->len);
+ if (n == 0xffffffff) {
+ LOG_ERR("SAF EC Portal unsupported erase size");
+ return -EAGAIN;
+ }
+ } else {
+ LOG_ERR("SAF EC Portal bad cmd");
+ return -EAGAIN;
+ }
+
+ LOG_DBG("%s params val done", __func__);
+
+ k_sem_take(&xdat->ecp_lock, K_FOREVER);
+
+ regs->SAF_ECP_INTEN = 0;
+ regs->SAF_ECP_STATUS = 0xffffffff;
+
+ /*
+ * TODO - Force SAF Done interrupt disabled until we have support
+ * from eSPI driver.
+ */
+ MCHP_GIRQ_ENCLR(MCHP_SAF_GIRQ) = MCHP_SAF_GIRQ_ECP_DONE_BIT;
+ MCHP_GIRQ_SRC(MCHP_SAF_GIRQ) = MCHP_SAF_GIRQ_ECP_DONE_BIT;
+
+ regs->SAF_ECP_FLAR = pckt->flash_addr;
+ regs->SAF_ECP_BFAR = (uint32_t)&slave_mem[0];
+
+ regs->SAF_ECP_CMD =
+ 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);
+
+ /* TODO when interrupts are available enable here */
+ regs->SAF_ECP_START = MCHP_SAF_ECP_START;
+
+ /* TODO
+ * ISR is in eSPI driver. Use polling until eSPI driver has been
+ * modified to provide callback for GIRQ19 SAF ECP Done.
+ */
+ rc = 0;
+ xdat->hwstatus = regs->SAF_ECP_STATUS;
+ while (!(xdat->hwstatus & MCHP_SAF_ECP_STS_DONE)) {
+ rc = xec_saf_spin_yield(&counter);
+ if (rc < 0) {
+ goto ecp_exit;
+ }
+ xdat->hwstatus = regs->SAF_ECP_STATUS;
+ }
+
+ /* clear hardware status and check for errors */
+ regs->SAF_ECP_STATUS = xdat->hwstatus;
+ if (xdat->hwstatus & MCHP_SAF_ECP_STS_ERR_MASK) {
+ rc = -EIO;
+ goto ecp_exit;
+ }
+
+ if (cmd == MCHP_SAF_ECP_CMD_CTYPE_READ0) {
+ memcpy(pckt->buf, slave_mem, pckt->len);
+ }
+
+ecp_exit:
+ k_sem_give(&xdat->ecp_lock);
+
+ 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_CTYPE_READ0);
+}
+
+/* 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_CTYPE_WRITE0);
+}
+
+/* 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_CTYPE_ERASE0);
+}
+
+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(dev);
+
+ return espi_manage_callback(&data->callbacks, callback, set);
+}
+
+static int espi_saf_xec_activate(const struct device *dev)
+{
+ const struct espi_saf_xec_config *cfg;
+ MCHP_SAF_HW_REGS *regs;
+
+ if (dev == NULL) {
+ return -EINVAL;
+ }
+
+ cfg = DEV_CFG(dev);
+ regs = (MCHP_SAF_HW_REGS *)cfg->saf_base_addr;
+
+ regs->SAF_FL_CFG_MISC |= MCHP_SAF_FL_CFG_MISC_SAF_EN;
+
+ return 0;
+}
+
+static int espi_saf_xec_init(const struct device *dev);
+
+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 struct espi_saf_xec_data espi_saf_xec_data;
+
+static const struct espi_saf_xec_config espi_saf_xec_config = {
+ .saf_base_addr = DT_INST_REG_ADDR_BY_IDX(0, 0),
+ .qmspi_base_addr = DT_INST_REG_ADDR_BY_IDX(0, 1),
+ .saf_comm_base_addr = DT_INST_REG_ADDR_BY_IDX(0, 2),
+ .poll_timeout = DT_INST_PROP_OR(inst, poll_timeout,
+ MCHP_SAF_FLASH_POLL_TIMEOUT),
+ .consec_rd_timeout = DT_INST_PROP_OR(
+ inst, consec_rd_timeout, MCHP_SAF_FLASH_CONSEC_READ_TIMEOUT),
+ .sus_chk_delay = DT_INST_PROP_OR(inst, sus_chk_delay,
+ MCHP_SAF_FLASH_SUS_CHK_DELAY),
+ .sus_rsm_interval = DT_INST_PROP_OR(inst, sus_rsm_interval,
+ MCHP_SAF_FLASH_SUS_RSM_INTERVAL),
+ .poll_interval = DT_INST_PROP_OR(inst, poll_interval,
+ MCHP_SAF_FLASH_POLL_INTERVAL),
+};
+
+DEVICE_DT_INST_DEFINE(0, &espi_saf_xec_init, device_pm_control_nop,
+ &espi_saf_xec_data, &espi_saf_xec_config, POST_KERNEL,
+ CONFIG_ESPI_SAF_INIT_PRIORITY, &espi_saf_xec_driver_api);
+
+static int espi_saf_xec_init(const struct device *dev)
+{
+ struct espi_saf_xec_data *data = DEV_DATA(dev);
+
+ /* ungate SAF clocks by disabling PCR sleep enable */
+ mchp_pcr_periph_slp_ctrl(PCR_ESPI_SAF, MCHP_PCR_SLEEP_DIS);
+
+ /* reset the SAF block */
+ mchp_pcr_periph_reset(PCR_ESPI_SAF);
+
+ /* Configure the channels and its capabilities based on build config */
+ ESPI_CAP_REGS->GLB_CAP0 |= MCHP_ESPI_GBL_CAP0_FC_SUPP;
+ ESPI_CAP_REGS->FC_CAP &= ~(MCHP_ESPI_FC_CAP_SHARE_MASK);
+ ESPI_CAP_REGS->FC_CAP |= MCHP_ESPI_FC_CAP_SHARE_MAF_SAF;
+
+ k_sem_init(&data->ecp_lock, 1, 1);
+
+ return 0;
+}
diff --git a/dts/arm/microchip/mec1501hsz.dtsi b/dts/arm/microchip/mec1501hsz.dtsi
index 2b7f646..0630f59 100644
--- a/dts/arm/microchip/mec1501hsz.dtsi
+++ b/dts/arm/microchip/mec1501hsz.dtsi
@@ -234,6 +234,17 @@
#size-cells = <0>;
status = "disabled";
};
+ espi_saf0: espi@40008000 {
+ compatible = "microchip,xec-espi-saf";
+ reg = < 0x40008000 0x400
+ 0x40070000 0x400
+ 0x40071000 0x400>;
+ label = "ESPI_SAF_0";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
timer0: timer@40000c00 {
compatible = "microchip,xec-timer";
clock-frequency = <48000000>;
diff --git a/dts/bindings/espi/microchip,xec-espi-saf.yaml b/dts/bindings/espi/microchip,xec-espi-saf.yaml
new file mode 100644
index 0000000..392413b
--- /dev/null
+++ b/dts/bindings/espi/microchip,xec-espi-saf.yaml
@@ -0,0 +1,44 @@
+# Copyright (c) 2019 Intel Corporation
+# Copyright (c) 2020 Microchip Technology Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+description: Microchip ESPI SAF controller
+
+compatible: "microchip,xec-espi-saf"
+
+include: espi-controller.yaml
+
+properties:
+ reg:
+ description: mmio register space
+ required: true
+
+ io_girq:
+ type: int
+ description: soc group irq index for eSPI I/O
+ required: false
+
+ 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
diff --git a/include/drivers/espi_saf.h b/include/drivers/espi_saf.h
new file mode 100644
index 0000000..508d8ff
--- /dev/null
+++ b/include/drivers/espi_saf.h
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2019 Intel Corporation.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @file
+ * @brief Public APIs for eSPI driver
+ */
+
+#ifndef ZEPHYR_INCLUDE_ESPI_SAF_H_
+#define ZEPHYR_INCLUDE_ESPI_SAF_H_
+
+#include <sys/__assert.h>
+#include <zephyr/types.h>
+#include <device.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief eSPI SAF Driver APIs
+ * @defgroup espi_interface ESPI Driver APIs
+ * @ingroup io_interfaces
+ * @{
+ */
+
+
+/**
+ *+----------------------------------------------------------------------+
+ *| |
+ *| eSPI host +-------------+ |
+ *| +-----------+ | Power | +----------+ |
+ *| |Out of band| | management | | GPIO | |
+ *| ------------ |processor | | controller | | sources | |
+ *| +-----------+ +-------------+ +----------+ |
+ *| | | | |
+ *| ------------ | | | |
+ *| +--------+ +---------------+ |
+ *| | | |
+ *| -----+ +--------+ +----------+ +----v-----+ |
+ *| | | LPC | | Tunneled | | Tunneled | |
+ *| | | bridge | | SMBus | | GPIO | |
+ *| | +--------+ +----------+ +----------+ |
+ *| | | | | |
+ *| | ------+ | | |
+ *| | | | | |
+ *| +------v-----+ +---v-------v-------------v----+ |
+ *| | eSPI Flash | | eSPI protocol block | |
+ *| | access +--->+ | |
+ *| +------------+ +------------------------------+ |
+ *| | |
+ *| ----------- | |
+ *| v |
+ *| XXXXXXXXXXXXXXXXXXXXXXX |
+ *| XXXXXXXXXXXXXXXXXXXXX |
+ *| XXXXXXXXXXXXXXXXXXX |
+ *+----------------------------------------------------------------------+
+ * |
+ * +-----------------+
+ * --------- | | | | | |
+ * | | | | | |
+ * --------- | + + + + | eSPI bus
+ * | CH0 CH1 CH2 CH3 | (logical channels)
+ * | + + + + |
+ * | | | | | |
+ * +-----------------+
+ * |
+ *+-----------------------------------------------------------------------+
+ *| eSPI slave |
+ *| |
+ *| CH0 | CH1 | CH2 | CH3 |
+ *| eSPI endpoint | VWIRE | OOB | Flash |
+ *+-----------------------------------------------------------------------+
+ * | |
+ * v |
+ * +---------+ |
+ * | Flash | Slave Attached Flash |
+ * +---------+ |
+ * |
+ */
+
+
+/**
+ * @cond INTERNAL_HIDDEN
+ *
+ */
+
+
+/** @endcond */
+
+struct espi_saf_hw_cfg;
+struct espi_saf_flash_cfg;
+struct espi_saf_pr;
+
+/**
+ * @brief eSPI SAF configuration parameters
+ */
+struct espi_saf_cfg {
+ uint8_t nflash_devices;
+ struct espi_saf_hw_cfg hwcfg;
+ struct espi_saf_flash_cfg *flash_cfgs;
+};
+
+/**
+ * @brief eSPI SAF transaction packet format
+ */
+struct espi_saf_packet {
+ uint32_t flash_addr;
+ uint8_t *buf;
+ uint32_t len;
+};
+
+/*
+ *defined in espi.h
+ * struct espi_callback
+ * typedef void (*espi_callback_handler_t)()
+ */
+
+/**
+ * @cond INTERNAL_HIDDEN
+ *
+ * eSPI driver API definition and system call entry points
+ *
+ * (Internal use only.)
+ */
+typedef int (*espi_saf_api_config)(const struct device *dev,
+ const struct espi_saf_cfg *cfg);
+
+typedef int (*espi_saf_api_set_protection_regions)(
+ const struct device *dev,
+ const struct espi_saf_protection *pr);
+
+typedef int (*espi_saf_api_activate)(const struct device *dev);
+
+typedef bool (*espi_saf_api_get_channel_status)(const struct device *dev);
+
+typedef int (*espi_saf_api_flash_read)(const struct device *dev,
+ struct espi_saf_packet *pckt);
+typedef int (*espi_saf_api_flash_write)(const struct device *dev,
+ struct espi_saf_packet *pckt);
+typedef int (*espi_saf_api_flash_erase)(const struct device *dev,
+ struct espi_saf_packet *pckt);
+/* Callbacks and traffic intercept */
+typedef int (*espi_saf_api_manage_callback)(const struct device *dev,
+ struct espi_callback *callback,
+ bool set);
+
+__subsystem struct espi_saf_driver_api {
+ espi_saf_api_config config;
+ espi_saf_api_set_protection_regions set_protection_regions;
+ espi_saf_api_activate activate;
+ espi_saf_api_get_channel_status get_channel_status;
+ espi_saf_api_flash_read flash_read;
+ espi_saf_api_flash_write flash_write;
+ espi_saf_api_flash_erase flash_erase;
+ espi_saf_api_manage_callback manage_callback;
+};
+
+/**
+ * @endcond
+ */
+
+/**
+ * @brief Configure operation of a eSPI controller.
+ *
+ * This routine provides a generic interface to override eSPI controller
+ * capabilities.
+ *
+ * If this eSPI controller is acting as slave, the values set here
+ * will be discovered as part through the GET_CONFIGURATION command
+ * issued by the eSPI master during initialization.
+ *
+ * If this eSPI controller is acting as master, the values set here
+ * will be used by eSPI master to determine minimum common capabilities with
+ * eSPI slave then send via SET_CONFIGURATION command.
+ *
+ * +--------+ +---------+ +------+ +---------+ +---------+
+ * | eSPI | | eSPI | | eSPI | | eSPI | | eSPI |
+ * | slave | | driver | | bus | | driver | | host |
+ * +--------+ +---------+ +------+ +---------+ +---------+
+ * | | | | |
+ * | espi_config | Set eSPI | Set eSPI | espi_config |
+ * +--------------+ ctrl regs | cap ctrl reg| +-----------+
+ * | +-------+ | +--------+ |
+ * | |<------+ | +------->| |
+ * | | | | |
+ * | | | | |
+ * | | | GET_CONFIGURATION | |
+ * | | +<------------------+ |
+ * | |<-----------| | |
+ * | | eSPI caps | | |
+ * | |----------->+ response | |
+ * | | |------------------>+ |
+ * | | | | |
+ * | | | SET_CONFIGURATION | |
+ * | | +<------------------+ |
+ * | | | accept | |
+ * | | +------------------>+ |
+ * + + + + +
+ *
+ * @param dev Pointer to the device structure for the driver instance.
+ * @param cfg the device runtime configuration for the eSPI controller.
+ *
+ * @retval 0 If successful.
+ * @retval -EIO General input / output error, failed to configure device.
+ * @retval -EINVAL invalid capabilities, failed to configure device.
+ * @retval -ENOTSUP capability not supported by eSPI slave.
+ */
+__syscall int espi_saf_config(const struct device *dev,
+ const struct espi_saf_cfg *cfg);
+
+static inline int z_impl_espi_saf_config(const struct device *dev,
+ const struct espi_saf_cfg *cfg)
+{
+ const struct espi_saf_driver_api *api =
+ (const struct espi_saf_driver_api *)dev->api;
+
+ return api->config(dev, cfg);
+}
+
+/**
+ * @brief Set one or more SAF protection regions
+ *
+ * This routine provides an interface to override the default flash
+ * protection regions of the SAF controller.
+ *
+ * @param dev Pointer to the device structure for the driver instance.
+ * @param pr Pointer to the SAF protection region structure.
+ *
+ * @retval 0 If successful.
+ * @retval -EIO General input / output error, failed to configure device.
+ * @retval -EINVAL invalid capabilities, failed to configure device.
+ * @retval -ENOTSUP capability not supported by eSPI slave.
+ */
+__syscall int espi_saf_set_protection_regions(
+ const struct device *dev,
+ const struct espi_saf_protection *pr);
+
+static inline int z_impl_espi_saf_set_protection_regions(
+ const struct device *dev,
+ const struct espi_saf_protection *pr)
+{
+ const struct espi_saf_driver_api *api =
+ (const struct espi_saf_driver_api *)dev->api;
+
+ return api->set_protection_regions(dev, pr);
+}
+
+/**
+ * @brief Activate SAF block
+ *
+ * This routine activates the SAF block and should only be
+ * called after SAF has been configured and the eSPI Master
+ * has enabled the Flash Channel.
+ *
+ * @param dev Pointer to the device structure for the driver instance.
+ *
+ * @retval 0 If successful
+ * @retval -EINVAL if failed to activate SAF.
+ */
+__syscall int espi_saf_activate(const struct device *dev);
+
+static inline int z_impl_espi_saf_activate(const struct device *dev)
+{
+ const struct espi_saf_driver_api *api =
+ (const struct espi_saf_driver_api *)dev->api;
+
+ return api->activate(dev);
+}
+
+/**
+ * @brief Query to see if SAF is ready
+ *
+ * This routine allows to check if SAF is ready before use.
+ *
+ * @param dev Pointer to the device structure for the driver instance.
+ *
+ * @retval true If eSPI SAF is ready.
+ * @retval false otherwise.
+ */
+__syscall bool espi_saf_get_channel_status(const struct device *dev);
+
+static inline bool z_impl_espi_saf_get_channel_status(
+ const struct device *dev)
+{
+ const struct espi_saf_driver_api *api =
+ (const struct espi_saf_driver_api *)dev->api;
+
+ return api->get_channel_status(dev);
+}
+
+/**
+ * @brief Sends a read request packet for slave attached flash.
+ *
+ * This routines provides an interface to send a request to read the flash
+ * component shared between the eSPI master and eSPI slaves.
+ *
+ * @param dev Pointer to the device structure for the driver instance.
+ * @param pckt Adddress of the representation of read flash transaction.
+ *
+ * @retval -ENOTSUP eSPI flash logical channel transactions not supported.
+ * @retval -EBUSY eSPI flash channel is not ready or disabled by master.
+ * @retval -EIO General input / output error, failed request to master.
+ */
+__syscall int espi_saf_flash_read(const struct device *dev,
+ struct espi_saf_packet *pckt);
+
+static inline int z_impl_espi_saf_flash_read(const struct device *dev,
+ struct espi_saf_packet *pckt)
+{
+ const struct espi_saf_driver_api *api =
+ (const struct espi_saf_driver_api *)dev->api;
+
+ if (!api->flash_read) {
+ return -ENOTSUP;
+ }
+
+ return api->flash_read(dev, pckt);
+}
+
+/**
+ * @brief Sends a write request packet for slave attached flash.
+ *
+ * This routines provides an interface to send a request to write to the flash
+ * components shared between the eSPI master and eSPI slaves.
+ *
+ * @param dev Pointer to the device structure for the driver instance.
+ * @param pckt Address of the representation of write flash transaction.
+ *
+ * @retval -ENOTSUP eSPI flash logical channel transactions not supported.
+ * @retval -EBUSY eSPI flash channel is not ready or disabled by master.
+ * @retval -EIO General input / output error, failed request to master.
+ */
+__syscall int espi_saf_flash_write(const struct device *dev,
+ struct espi_saf_packet *pckt);
+
+static inline int z_impl_espi_saf_flash_write(const struct device *dev,
+ struct espi_saf_packet *pckt)
+{
+ const struct espi_saf_driver_api *api =
+ (const struct espi_saf_driver_api *)dev->api;
+
+ if (!api->flash_write) {
+ return -ENOTSUP;
+ }
+
+ return api->flash_write(dev, pckt);
+}
+
+/**
+ * @brief Sends a write request packet for slave attached flash.
+ *
+ * This routines provides an interface to send a request to write to the flash
+ * components shared between the eSPI master and eSPI slaves.
+ *
+ * @param dev Pointer to the device structure for the driver instance.
+ * @param pckt Address of the representation of erase flash transaction.
+ *
+ * @retval -ENOTSUP eSPI flash logical channel transactions not supported.
+ * @retval -EBUSY eSPI flash channel is not ready or disabled by master.
+ * @retval -EIO General input / output error, failed request to master.
+ */
+__syscall int espi_saf_flash_erase(const struct device *dev,
+ struct espi_saf_packet *pckt);
+
+static inline int z_impl_espi_saf_flash_erase(const struct device *dev,
+ struct espi_saf_packet *pckt)
+{
+ const struct espi_saf_driver_api *api =
+ (const struct espi_saf_driver_api *)dev->api;
+
+ if (!api->flash_erase) {
+ return -ENOTSUP;
+ }
+
+ return api->flash_erase(dev, pckt);
+}
+
+/**
+ * Callback model
+ *
+ *+-------+ +-------------+ +------+ +---------+
+ *| App | | eSPI driver | | HW | |eSPI Host|
+ *+---+---+ +-------+-----+ +---+--+ +----+----+
+ * | | | |
+ * | espi_init_callback | | |
+ * +----------------------------> | | |
+ * | espi_add_callback | |
+ * +----------------------------->+ |
+ * | | | eSPI reset | eSPI host
+ * | | IRQ +<------------+ resets the
+ * | | <-----------+ | bus
+ * | | | |
+ * | | Processed | |
+ * | | within the | |
+ * | | driver | |
+ * | | | |
+
+ * | | | VW CH ready| eSPI host
+ * | | IRQ +<------------+ enables VW
+ * | | <-----------+ | channel
+ * | | | |
+ * | | Processed | |
+ * | | within the | |
+ * | | driver | |
+ * | | | |
+ * | | | Memory I/O | Peripheral
+ * | | <-------------+ event
+ * | +<------------+ |
+ * +<-----------------------------+ callback | |
+ * | Report peripheral event | | |
+ * | and data for the event | | |
+ * | | | |
+ * | | | SLP_S5 | eSPI host
+ * | | <-------------+ send VWire
+ * | +<------------+ |
+ * +<-----------------------------+ callback | |
+ * | App enables/configures | | |
+ * | discrete regulator | | |
+ * | | | |
+ * | espi_send_vwire_signal | | |
+ * +------------------------------>------------>|------------>|
+ * | | | |
+ * | | | HOST_RST | eSPI host
+ * | | <-------------+ send VWire
+ * | +<------------+ |
+ * +<-----------------------------+ callback | |
+ * | App reset host-related | | |
+ * | data structures | | |
+ * | | | |
+ * | | | C10 | eSPI host
+ * | | +<------------+ send VWire
+ * | <-------------+ |
+ * <------------------------------+ | |
+ * | App executes | | |
+ * + power mgmt policy | | |
+ */
+
+/**
+ * @brief Helper to initialize a struct espi_callback properly.
+ *
+ * @param callback A valid Application's callback structure pointer.
+ * @param handler A valid handler function pointer.
+ * @param evt_type indicates the eSPI event relevant for the handler.
+ * for VWIRE_RECEIVED event the data will indicate the new level asserted
+ */
+static inline void espi_saf_init_callback(struct espi_callback *callback,
+ espi_callback_handler_t handler,
+ enum espi_bus_event evt_type)
+{
+ __ASSERT(callback, "Callback pointer should not be NULL");
+ __ASSERT(handler, "Callback handler pointer should not be NULL");
+
+ callback->handler = handler;
+ callback->evt_type = evt_type;
+}
+
+/**
+ * @brief Add an application callback.
+ * @param dev Pointer to the device structure for the driver instance.
+ * @param callback A valid Application's callback structure pointer.
+ * @return 0 if successful, negative errno code on failure.
+ *
+ * @note Callbacks may be added to the device from within a callback
+ * handler invocation, but whether they are invoked for the current
+ * eSPI event is not specified.
+ *
+ * Note: enables to add as many callback as needed on the same device.
+ */
+static inline int espi_saf_add_callback(const struct device *dev,
+ struct espi_callback *callback)
+{
+ const struct espi_saf_driver_api *api =
+ (const struct espi_saf_driver_api *)dev->api;
+
+ if (!api->manage_callback) {
+ return -ENOTSUP;
+ }
+
+ return api->manage_callback(dev, callback, true);
+}
+
+/**
+ * @brief Remove an application callback.
+ * @param dev Pointer to the device structure for the driver instance.
+ * @param callback A valid application's callback structure pointer.
+ * @return 0 if successful, negative errno code on failure.
+ *
+ * @warning It is explicitly permitted, within a callback handler, to
+ * remove the registration for the callback that is running, i.e. @p
+ * callback. Attempts to remove other registrations on the same
+ * device may result in undefined behavior, including failure to
+ * invoke callbacks that remain registered and unintended invocation
+ * of removed callbacks.
+ *
+ * Note: enables to remove as many callbacks as added through
+ * espi_add_callback().
+ */
+static inline int espi_saf_remove_callback(const struct device *dev,
+ struct espi_callback *callback)
+{
+ const struct espi_saf_driver_api *api =
+ (const struct espi_saf_driver_api *)dev->api;
+
+ if (!api->manage_callback) {
+ return -ENOTSUP;
+ }
+
+ return api->manage_callback(dev, callback, false);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+#include <syscalls/espi_saf.h>
+#endif /* ZEPHYR_INCLUDE_ESPI_SAF_H_ */
diff --git a/soc/arm/microchip_mec/common/soc_espi_saf.h b/soc/arm/microchip_mec/common/soc_espi_saf.h
new file mode 100644
index 0000000..7695904
--- /dev/null
+++ b/soc/arm/microchip_mec/common/soc_espi_saf.h
@@ -0,0 +1,407 @@
+/*
+ * 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 <stdint.h>
+#include <sys/util.h>
+#include <soc.h>
+
+#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 0x23221100
+#define MCHP_SAF_TAG_MAP1_DFLT 0x77677767
+#define MCHP_SAF_TAG_MAP2_DFLT 0x00000005
+
+/*
+ * Default QMSPI clock divider and chip select timing.
+ * QMSPI master clock is 48MHz AHB clock.
+ */
+#define MCHP_SAF_QMSPI_CLK_DIV 2U
+#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 */
+/* #define SAF_QMSPI_DESCR12 0x0002D40E */
+
+/*
+ * 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)
+
+/*
+ * 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_DMA_4B | 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_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)
+
+#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)
+
+/* 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
+
+#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_DMA_4B | 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 SAF_OPCODE_REG_VAL(0x06U, 0x75U, 0x7aU, 0x05U)
+#define MCHP_W25Q256_OPB SAF_OPCODE_REG_VAL(0x20U, 0x52U, 0xd8U, 0x02U)
+#define MCHP_W25Q256_OPC SAF_OPCODE_REG_VAL(0xebU, 0xffU, 0xa5U, 0x35U)
+
+#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)
+
+/* 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_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)
+
+struct espi_saf_hw_cfg {
+ uint32_t qmspi_freq_hz;
+ uint32_t qmspi_cs_timing;
+ uint8_t qmspi_cpha;
+ uint8_t flags;
+ uint32_t generic_descr[MCHP_SAF_NUM_GENERIC_DESCR];
+ uint32_t tag_map[MCHP_ESPI_SAF_TAGMAP_MAX];
+};
+
+/*
+ * SAF local flash configuration.
+ * 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
+ * QMSPI descriptors describing SPI opcode transmit and
+ * data read.
+ * SAF controller Poll2 Mast value specific for this flash device
+ * SAF continuous mode prefix register value for those flashes requireing
+ * a prefix byte transmitted before the enter continuous mode command.
+ * Start QMSPI descriptor numbers.
+ * miscellaneous flags.
+ */
+
+/* Flags */
+#define MCHP_FLASH_FLAG_ADDR32 BIT(0)
+
+struct espi_saf_flash_cfg {
+ uint32_t flashsz;
+ uint32_t opa;
+ uint32_t opb;
+ uint32_t opc;
+ uint16_t poll2_mask;
+ uint16_t cont_prefix;
+ uint16_t cs_cfg_descr_ids;
+ uint16_t flags;
+ 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_ */
diff --git a/soc/arm/microchip_mec/mec1501/soc.h b/soc/arm/microchip_mec/mec1501/soc.h
index 24c984b..dd48cc1 100644
--- a/soc/arm/microchip_mec/mec1501/soc.h
+++ b/soc/arm/microchip_mec/mec1501/soc.h
@@ -17,6 +17,7 @@
#include "../common/soc_gpio.h"
#include "../common/soc_pins.h"
#include "../common/soc_espi_channels.h"
+#include "../common/soc_espi_saf.h"
#endif