diff --git a/drivers/espi/CMakeLists.txt b/drivers/espi/CMakeLists.txt index 601462a55e1..d26e50cbd13 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 e7a7565e836..debbc921bda 100644 --- a/drivers/espi/Kconfig.xec +++ b/drivers/espi/Kconfig.xec @@ -37,4 +37,19 @@ config ESPI_PERIPHERAL_UART_SOC_MAPPING 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 00000000000..17714e2da7d --- /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 +#include +#include +#include +#include +#include + +#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 2b7f646a6dd..0630f594bb5 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 00000000000..392413bd613 --- /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 00000000000..508d8ffc56d --- /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 +#include +#include + +#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 +#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 00000000000..7695904cc4f --- /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 +#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 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 24c984b6b17..dd48cc15cad 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