drivers: espi: npcx: introduce espi taf driver

This CL implements espi taf read/write/erase function for NPCX.

Signed-off-by: Tom Chang <CHChang19@nuvoton.com>
This commit is contained in:
Tom Chang 2023-12-08 17:25:35 +08:00 committed by Carles Cufí
commit 4dc7c89f40
16 changed files with 928 additions and 13 deletions

View file

@ -7,6 +7,7 @@ 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_ESPI_TAF_NPCX espi_taf_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_XEC espi_saf_mchp_xec.c)

View file

@ -58,6 +58,36 @@ config ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_RING_BUF_SIZE
The size of the ring buffer in byte used by the Port80 ISR to store
Postcodes from Host.
config ESPI_TAF_NPCX
bool "Nuvoton NPCX embedded controller (EC) ESPI TAF driver"
depends on SOC_SERIES_NPCX4
help
This option enables the Intel Enhanced Serial Peripheral Interface
Target Attached Flash (eSPI TAF) for NPCX4 family of processors.
choice ESPI_TAF_ACCESS_MODE_CHOICE
prompt "eSPI TAF Read Access Mode"
default ESPI_TAF_AUTO_MODE
config ESPI_TAF_AUTO_MODE
bool "eSPI TAF Automatic Mode"
help
This is the setting to use auto mode for eSPI TAF read.
config ESPI_TAF_MANUAL_MODE
bool "eSPI TAF Manual Mode"
help
This is the setting to use manual mode for eSPI TAF read.
endchoice
config ESPI_TAF_PR_NUM
int "Sets of protection region settings"
default 16
help
This size is display how many group of slave attached flash protection
region.
# The default value 'y' for the existing options if ESPI_NPCX is selected.
if ESPI_NPCX

View file

@ -7,6 +7,7 @@
#define DT_DRV_COMPAT nuvoton_npcx_espi
#include <assert.h>
#include <stdlib.h>
#include <zephyr/drivers/espi.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/clock_control.h>
@ -74,8 +75,8 @@ struct espi_npcx_data {
((hdr & 0xf0000) >> 8))
/* Flash channel maximum payload size */
#define NPCX_ESPI_FLASH_MAX_RX_PAYLOAD 64
#define NPCX_ESPI_FLASH_MAX_TX_PAYLOAD 16
#define NPCX_ESPI_FLASH_MAX_RX_PAYLOAD DT_INST_PROP(0, rx_plsize)
#define NPCX_ESPI_FLASH_MAX_TX_PAYLOAD DT_INST_PROP(0, tx_plsize)
/* eSPI cycle type field for OOB and FLASH channels */
#define ESPI_FLASH_READ_CYCLE_TYPE 0x00
@ -275,6 +276,19 @@ static void espi_bus_cfg_update_isr(const struct device *dev)
NPCX_ESPI_HOST_CH_EN(NPCX_ESPI_CH_VW))) {
espi_vw_send_bootload_done(dev);
}
#if (defined(CONFIG_ESPI_FLASH_CHANNEL) && defined(CONFIG_ESPI_SAF))
/* If CONFIG_ESPI_SAF is set, set to auto or manual mode accroding
* to configuration.
*/
if (IS_BIT_SET(inst->ESPICFG, NPCX_ESPICFG_FLCHANMODE)) {
#if defined(CONFIG_ESPI_TAF_AUTO_MODE)
inst->FLASHCTL |= BIT(NPCX_FLASHCTL_SAF_AUTO_READ);
#else
inst->FLASHCTL &= ~BIT(NPCX_FLASHCTL_SAF_AUTO_READ);
#endif
}
#endif
}
#if defined(CONFIG_ESPI_OOB_CHANNEL)
@ -288,12 +302,82 @@ static void espi_bus_oob_rx_isr(const struct device *dev)
#endif
#if defined(CONFIG_ESPI_FLASH_CHANNEL)
#if defined(CONFIG_ESPI_SAF)
static struct espi_taf_pckt taf_pckt;
static uint32_t espi_taf_parse(const struct device *dev)
{
struct espi_reg *const inst = HAL_INSTANCE(dev);
struct npcx_taf_head taf_head;
uint32_t taf_addr;
uint8_t i, roundsize;
/* Get type, length and tag from RX buffer */
memcpy(&taf_head, (void *)&inst->FLASHRXBUF[0], sizeof(taf_head));
taf_pckt.type = taf_head.type;
taf_pckt.len = (((uint16_t)taf_head.tag_hlen & 0xF) << 8) | taf_head.llen;
taf_pckt.tag = taf_head.tag_hlen >> 4;
if ((taf_pckt.len == 0) && ((taf_pckt.type & 0xF) == NPCX_ESPI_TAF_REQ_READ)) {
taf_pckt.len = KB(4);
}
/* Get address from RX buffer */
taf_addr = inst->FLASHRXBUF[1];
taf_pckt.addr = sys_cpu_to_be32(taf_addr);
/* Get written data if eSPI TAF write */
if ((taf_pckt.type & 0xF) == NPCX_ESPI_TAF_REQ_WRITE) {
roundsize = DIV_ROUND_UP(taf_pckt.len, sizeof(uint32_t));
for (i = 0; i < roundsize; i++) {
taf_pckt.src[i] = inst->FLASHRXBUF[2 + i];
}
}
return (uint32_t)&taf_pckt;
}
#endif /* CONFIG_ESPI_SAF */
static void espi_bus_flash_rx_isr(const struct device *dev)
{
struct espi_reg *const inst = HAL_INSTANCE(dev);
struct espi_npcx_data *const data = dev->data;
LOG_DBG("%s", __func__);
k_sem_give(&data->flash_rx_lock);
/* Controller Attached Flash Access */
if ((inst->ESPICFG & BIT(NPCX_ESPICFG_FLCHANMODE)) == 0) {
k_sem_give(&data->flash_rx_lock);
} else { /* Target Attached Flash Access */
#if defined(CONFIG_ESPI_SAF)
struct espi_event evt = {
.evt_type = ESPI_BUS_SAF_NOTIFICATION,
.evt_details = ESPI_CHANNEL_FLASH,
.evt_data = espi_taf_parse(dev),
};
espi_send_callbacks(&data->callbacks, dev, evt);
#else
LOG_WRN("ESPI TAF not supported");
#endif
}
}
static void espi_bus_completion_sent_isr(const struct device *dev)
{
struct espi_reg *const inst = HAL_INSTANCE(dev);
/* check that ESPISTS.FLNACS is clear. */
if (IS_BIT_SET(inst->ESPISTS, NPCX_ESPISTS_FLNACS)) {
LOG_ERR("ESPISTS_FLNACS not clear\r\n");
}
/* flash operation is done, Make sure the TAFS transmit buffer is empty */
if (IS_BIT_SET(inst->FLASHCTL, NPCX_FLASHCTL_FLASH_TX_AVAIL)) {
LOG_ERR("FLASH_TX_AVAIL not clear\r\n");
}
/* In auto mode, release FLASH_NP_FREE here to get next SAF request.*/
if (IS_BIT_SET(inst->FLASHCTL, NPCX_FLASHCTL_SAF_AUTO_READ)) {
inst->FLASHCTL |= BIT(NPCX_FLASHCTL_FLASH_NP_FREE);
}
}
#endif
@ -307,6 +391,7 @@ const struct espi_bus_isr espi_bus_isr_tbl[] = {
#endif
#if defined(CONFIG_ESPI_FLASH_CHANNEL)
NPCX_ESPI_BUS_INT_ITEM(FLASHRX, espi_bus_flash_rx_isr),
NPCX_ESPI_BUS_INT_ITEM(FLNACS, espi_bus_completion_sent_isr),
#endif
};

View file

@ -0,0 +1,466 @@
/*
* Copyright (c) 2023 Nuvoton Technology Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT nuvoton_npcx_espi_taf
#include <soc.h>
#include <zephyr/drivers/espi.h>
#include <zephyr/drivers/espi_saf.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(espi_taf, CONFIG_ESPI_LOG_LEVEL);
static const struct device *const spi_dev = DEVICE_DT_GET(DT_ALIAS(taf_flash));
struct espi_taf_npcx_config {
uintptr_t base;
uintptr_t mapped_addr;
uintptr_t rx_plsz;
enum NPCX_ESPI_TAF_ERASE_BLOCK_SIZE erase_sz;
enum NPCX_ESPI_TAF_MAX_READ_REQ max_rd_sz;
};
struct espi_taf_npcx_data {
sys_slist_t callbacks;
};
#define HAL_INSTANCE(dev) \
((struct espi_reg *)((const struct espi_taf_npcx_config *) \
(dev)->config)->base)
#define FLBASE_ADDR ( \
GET_FIELD(inst->FLASHBASE, NPCX_FLASHBASE_FLBASE_ADDR) \
<< GET_FIELD_POS(NPCX_FLASHBASE_FLBASE_ADDR))
#define PRTR_BADDR(i) ( \
GET_FIELD(inst->FLASH_PRTR_BADDR[i], NPCX_FLASH_PRTR_BADDR) \
<< GET_FIELD_POS(NPCX_FLASH_PRTR_BADDR))
#define PRTR_HADDR(i) ( \
GET_FIELD(inst->FLASH_PRTR_HADDR[i], NPCX_FLASH_PRTR_HADDR) \
<< GET_FIELD_POS(NPCX_FLASH_PRTR_HADDR)) | 0xFFF;
/* Check access region of read request is protected or not */
static bool espi_taf_check_read_protect(const struct device *dev, uint32_t addr, uint32_t len,
uint8_t tag)
{
struct espi_reg *const inst = HAL_INSTANCE(dev);
uint32_t flash_addr = addr;
uint8_t i;
uint16_t override_rd;
uint32_t base, high;
bool rdpr;
flash_addr += FLBASE_ADDR;
for (i = 0; i < CONFIG_ESPI_TAF_PR_NUM; i++) {
base = PRTR_BADDR(i);
high = PRTR_HADDR(i);
rdpr = IS_BIT_SET(inst->FLASH_PRTR_BADDR[i], NPCX_FRGN_RPR);
override_rd = GET_FIELD(inst->FLASH_RGN_TAG_OVR[i], NPCX_FLASH_TAG_OVR_RPR);
if (rdpr && !IS_BIT_SET(override_rd, tag) &&
(base <= flash_addr + len - 1 && flash_addr <= high)) {
return true;
}
}
return false;
}
/* Check access region of write request is protected or not */
static bool espi_taf_check_write_protect(const struct device *dev, uint32_t addr,
uint32_t len, uint8_t tag)
{
struct espi_reg *const inst = HAL_INSTANCE(dev);
uint32_t flash_addr = addr;
uint8_t i;
uint16_t override_wr;
uint32_t base, high;
bool wrpr;
flash_addr += FLBASE_ADDR;
for (i = 0; i < CONFIG_ESPI_TAF_PR_NUM; i++) {
base = PRTR_BADDR(i);
high = PRTR_HADDR(i);
wrpr = IS_BIT_SET(inst->FLASH_PRTR_BADDR[i], NPCX_FRGN_WPR);
override_wr = GET_FIELD(inst->FLASH_RGN_TAG_OVR[i], NPCX_FLASH_TAG_OVR_WPR);
if (wrpr && !IS_BIT_SET(override_wr, tag) &&
(base <= flash_addr + len - 1 && flash_addr <= high)) {
return true;
}
}
return false;
}
static int espi_taf_npcx_configure(const struct device *dev, const struct espi_saf_cfg *cfg)
{
struct espi_reg *const inst = HAL_INSTANCE(dev);
#if defined(CONFIG_ESPI_TAF_AUTO_MODE)
inst->FLASHCTL |= BIT(NPCX_FLASHCTL_SAF_AUTO_READ);
#else
inst->FLASHCTL &= ~BIT(NPCX_FLASHCTL_SAF_AUTO_READ);
#endif
return 0;
}
static int espi_taf_npcx_set_pr(const struct device *dev, const struct espi_saf_protection *pr)
{
struct espi_reg *const inst = HAL_INSTANCE(dev);
const struct espi_saf_pr *preg = pr->pregions;
size_t n = pr->nregions;
uint8_t regnum;
uint16_t bitmask, offset;
uint32_t rw_pr, override_rw;
if ((dev == NULL) || (pr == NULL)) {
return -EINVAL;
}
if (pr->nregions >= CONFIG_ESPI_TAF_PR_NUM) {
return -EINVAL;
}
while (n--) {
regnum = preg->pr_num;
if (regnum >= CONFIG_ESPI_TAF_PR_NUM) {
return -EINVAL;
}
rw_pr = preg->master_bm_we << NPCX_FRGN_WPR;
rw_pr = rw_pr | (preg->master_bm_rd << NPCX_FRGN_RPR);
if (preg->flags) {
bitmask = BIT_MASK(GET_FIELD_SZ(NPCX_FLASH_PRTR_BADDR));
offset = GET_FIELD_POS(NPCX_FLASH_PRTR_BADDR);
inst->FLASH_PRTR_BADDR[regnum] = ((preg->start & bitmask) << offset)
| rw_pr;
bitmask = BIT_MASK(GET_FIELD_SZ(NPCX_FLASH_PRTR_HADDR));
offset = GET_FIELD_POS(NPCX_FLASH_PRTR_HADDR);
inst->FLASH_PRTR_HADDR[regnum] = (preg->end & bitmask) << offset;
}
override_rw = (preg->override_r << 16) | preg->override_w;
inst->FLASH_RGN_TAG_OVR[regnum] = override_rw;
preg++;
}
return 0;
}
static int espi_taf_npcx_activate(const struct device *dev)
{
struct espi_reg *const inst = HAL_INSTANCE(dev);
inst->FLASHCTL &= ~BIT(NPCX_FLASHCTL_AUTO_RD_DIS_CTL);
inst->FLASHCTL &= ~BIT(NPCX_FLASHCTL_BLK_FLASH_NP_FREE);
return 0;
}
static bool espi_taf_npcx_channel_ready(const struct device *dev)
{
struct espi_reg *const inst = HAL_INSTANCE(dev);
if (!IS_BIT_SET(inst->ESPICFG, NPCX_ESPICFG_FLCHANMODE)) {
return false;
}
return true;
}
/* This routine set FLASH_C_AVAIL for standard request */
static void taf_set_flash_c_avail(const struct device *dev)
{
struct espi_reg *const inst = HAL_INSTANCE(dev);
uint32_t tmp = inst->FLASHCTL;
/*
* Clear FLASHCTL_FLASH_NP_FREE to avoid host puts a flash
* standard request command at here.
*/
tmp &= NPCX_FLASHCTL_ACCESS_MASK;
/* Set FLASHCTL_FLASH_TX_AVAIL */
tmp |= BIT(NPCX_FLASHCTL_FLASH_TX_AVAIL);
inst->FLASHCTL = tmp;
}
/* This routine release FLASH_NP_FREE for standard request */
static void taf_release_flash_np_free(const struct device *dev)
{
struct espi_reg *const inst = HAL_INSTANCE(dev);
uint32_t tmp = inst->FLASHCTL;
/*
* Clear FLASHCTL_FLASH_TX_AVAIL to avoid host puts a
* GET_FLASH_C command at here.
*/
tmp &= NPCX_FLASHCTL_ACCESS_MASK;
/* Release FLASH_NP_FREE */
tmp |= BIT(NPCX_FLASHCTL_FLASH_NP_FREE);
inst->FLASHCTL = tmp;
}
static int taf_npcx_completion_handler(const struct device *dev, uint32_t *buffer)
{
uint16_t size = DIV_ROUND_UP((uint8_t)(buffer[0]) + 1, sizeof(uint32_t));
struct espi_reg *const inst = HAL_INSTANCE(dev);
struct npcx_taf_head *head = (struct npcx_taf_head *)buffer;
uint8_t i;
/* Check the Flash Access TX Queue is empty by polling
* FLASH_TX_AVAIL.
*/
if (WAIT_FOR(IS_BIT_SET(inst->FLASHCTL, NPCX_FLASHCTL_FLASH_TX_AVAIL),
NPCX_FLASH_CHK_TIMEOUT, NULL)) {
LOG_ERR("Check TX Queue Is Empty Timeout");
return -EBUSY;
}
/* Check ESPISTS.FLNACS is clear (no slave completion is detected) */
if (WAIT_FOR(IS_BIT_SET(inst->ESPISTS, NPCX_ESPISTS_FLNACS),
NPCX_FLASH_CHK_TIMEOUT, NULL)) {
LOG_ERR("Check Slave Completion Timeout");
return -EBUSY;
}
/* Write packet to FLASHTXBUF */
for (i = 0; i < size; i++) {
inst->FLASHTXBUF[i] = buffer[i];
}
/* Set the FLASHCTL.FLASH_TX_AVAIL bit to 1 to enqueue the packet */
taf_set_flash_c_avail(dev);
/* Release FLASH_NP_FREE here to ready get next TAF request */
if ((head->type != CYC_SCS_CMP_WITH_DATA_FIRST) &&
(head->type != CYC_SCS_CMP_WITH_DATA_MIDDLE)) {
taf_release_flash_np_free(dev);
}
return 0;
}
static int espi_taf_npcx_flash_read(const struct device *dev, struct espi_saf_packet *pckt)
{
struct espi_reg *const inst = HAL_INSTANCE(dev);
struct espi_taf_npcx_config *config = ((struct espi_taf_npcx_config *)(dev)->config);
struct espi_taf_npcx_pckt *taf_data_ptr = (struct espi_taf_npcx_pckt *)pckt->buf;
uint8_t *data_ptr = (uint8_t *)taf_data_ptr->data;
uint8_t cycle_type = CYC_SCS_CMP_WITH_DATA_ONLY;
uint32_t total_len = pckt->len;
uint32_t len = total_len;
uint32_t addr = pckt->flash_addr;
uint8_t flash_req_size = GET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_FLASHREQSIZE);
uint8_t target_max_size = GET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_FLREQSUP);
uint16_t max_read_req = 32 << flash_req_size;
struct npcx_taf_head taf_head;
int rc;
if (flash_req_size > target_max_size) {
LOG_DBG("Exceeded the maximum supported length");
if (target_max_size == 0) {
target_max_size = 1;
}
max_read_req = 32 << target_max_size;
}
if (total_len > max_read_req) {
LOG_ERR("Exceeded the limitation of read length");
return -EINVAL;
}
if (espi_taf_check_read_protect(dev, addr, len, taf_data_ptr->tag)) {
LOG_ERR("Access protect region");
return -EINVAL;
}
if (total_len <= config->rx_plsz) {
cycle_type = CYC_SCS_CMP_WITH_DATA_ONLY;
len = total_len;
} else {
cycle_type = CYC_SCS_CMP_WITH_DATA_FIRST;
len = config->rx_plsz;
}
do {
data_ptr = (uint8_t *)taf_data_ptr->data;
taf_head.pkt_len = len + NPCX_TAF_CMP_HEADER_LEN;
taf_head.type = cycle_type;
taf_head.tag_hlen = (taf_data_ptr->tag << 4) | ((len & 0xF00) >> 8);
taf_head.llen = len & 0xFF;
memcpy(data_ptr, &taf_head, sizeof(taf_head));
rc = flash_read(spi_dev, addr, data_ptr + 4, len);
if (rc) {
LOG_ERR("flash read fail 0x%x", rc);
return -EIO;
}
rc = taf_npcx_completion_handler(dev, (uint32_t *)taf_data_ptr->data);
if (rc) {
LOG_ERR("espi taf completion handler fail");
return rc;
}
total_len -= len;
addr += len;
if (total_len <= config->rx_plsz) {
cycle_type = CYC_SCS_CMP_WITH_DATA_LAST;
len = total_len;
} else {
cycle_type = CYC_SCS_CMP_WITH_DATA_MIDDLE;
}
} while (total_len);
return 0;
}
static int espi_taf_npcx_flash_write(const struct device *dev, struct espi_saf_packet *pckt)
{
struct espi_taf_npcx_pckt *taf_data_ptr = (struct espi_taf_npcx_pckt *)pckt->buf;
uint8_t *data_ptr = (uint8_t *)(taf_data_ptr->data);
struct npcx_taf_head taf_head;
int rc;
if (espi_taf_check_write_protect(dev, pckt->flash_addr,
pckt->len, taf_data_ptr->tag)) {
LOG_ERR("Access protection region");
return -EINVAL;
}
rc = flash_write(spi_dev, pckt->flash_addr, data_ptr, pckt->len);
if (rc) {
LOG_ERR("flash write fail 0x%x", rc);
return -EIO;
}
taf_head.pkt_len = NPCX_TAF_CMP_HEADER_LEN;
taf_head.type = CYC_SCS_CMP_WITHOUT_DATA;
taf_head.tag_hlen = (taf_data_ptr->tag << 4);
taf_head.llen = 0x0;
memcpy(data_ptr, &taf_head, sizeof(taf_head));
rc = taf_npcx_completion_handler(dev, (uint32_t *)taf_data_ptr->data);
if (rc) {
LOG_ERR("espi taf completion handler fail");
return rc;
}
return 0;
}
static int espi_taf_npcx_flash_erase(const struct device *dev, struct espi_saf_packet *pckt)
{
struct espi_taf_npcx_pckt *taf_data_ptr = (struct espi_taf_npcx_pckt *)pckt->buf;
uint8_t *data_ptr = (uint8_t *)taf_data_ptr->data;
uint32_t addr = pckt->flash_addr;
uint32_t len = pckt->len;
struct npcx_taf_head taf_head;
int rc;
if (espi_taf_check_write_protect(dev, addr, len, taf_data_ptr->tag)) {
LOG_ERR("Access protection region");
return -EINVAL;
}
rc = flash_erase(spi_dev, addr, len);
if (rc) {
LOG_ERR("flash erase fail");
return -EIO;
}
taf_head.pkt_len = NPCX_TAF_CMP_HEADER_LEN;
taf_head.type = CYC_SCS_CMP_WITHOUT_DATA;
taf_head.tag_hlen = (taf_data_ptr->tag << 4);
taf_head.llen = 0x0;
memcpy(data_ptr, &taf_head, sizeof(taf_head));
rc = taf_npcx_completion_handler(dev, (uint32_t *)taf_data_ptr->data);
if (rc) {
LOG_ERR("espi taf completion handler fail");
return rc;
}
return 0;
}
static int espi_taf_npcx_flash_unsuccess(const struct device *dev, struct espi_saf_packet *pckt)
{
struct espi_taf_npcx_pckt *taf_data_ptr
= (struct espi_taf_npcx_pckt *)pckt->buf;
uint8_t *data_ptr = (uint8_t *)taf_data_ptr->data;
struct npcx_taf_head taf_head;
int rc;
taf_head.pkt_len = NPCX_TAF_CMP_HEADER_LEN;
taf_head.type = CYC_UNSCS_CMP_WITHOUT_DATA_ONLY;
taf_head.tag_hlen = (taf_data_ptr->tag << 4);
taf_head.llen = 0x0;
memcpy(data_ptr, &taf_head, sizeof(taf_head));
rc = taf_npcx_completion_handler(dev, (uint32_t *)taf_data_ptr->data);
if (rc) {
LOG_ERR("espi taf completion handler fail");
return rc;
}
return 0;
}
static int espi_taf_npcx_init(const struct device *dev)
{
struct espi_reg *const inst = HAL_INSTANCE(dev);
struct espi_taf_npcx_config *config = ((struct espi_taf_npcx_config *)(dev)->config);
SET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_FLCAPA,
NPCX_FLASH_SHARING_CAP_SUPP_TAF_AND_CAF);
SET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_TRGFLEBLKSIZE,
BIT(config->erase_sz));
SET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_FLREQSUP,
config->max_rd_sz);
inst->FLASHBASE = config->mapped_addr;
return 0;
}
static const struct espi_saf_driver_api espi_taf_npcx_driver_api = {
.config = espi_taf_npcx_configure,
.set_protection_regions = espi_taf_npcx_set_pr,
.activate = espi_taf_npcx_activate,
.get_channel_status = espi_taf_npcx_channel_ready,
.flash_read = espi_taf_npcx_flash_read,
.flash_write = espi_taf_npcx_flash_write,
.flash_erase = espi_taf_npcx_flash_erase,
.flash_unsuccess = espi_taf_npcx_flash_unsuccess,
};
static struct espi_taf_npcx_data npcx_espi_taf_data;
static const struct espi_taf_npcx_config espi_taf_npcx_config = {
.base = DT_INST_REG_ADDR(0),
.mapped_addr = DT_INST_PROP(0, mapped_addr),
.rx_plsz = DT_PROP(DT_INST_PARENT(0), rx_plsize),
.erase_sz = DT_INST_STRING_TOKEN(0, erase_sz),
.max_rd_sz = DT_INST_STRING_TOKEN(0, max_read_sz),
};
DEVICE_DT_INST_DEFINE(0, &espi_taf_npcx_init, NULL,
&npcx_espi_taf_data, &espi_taf_npcx_config,
PRE_KERNEL_2, CONFIG_ESPI_INIT_PRIORITY,
&espi_taf_npcx_driver_api);

View file

@ -306,6 +306,17 @@
buffer-tx-size = <128>;
shi-cs-wui =<&wui_io53>;
};
espi0: espi@4000a000 {
rx-plsize = <64>;
tx-plsize = <64>;
espi_taf: espitaf@4000a000 {
compatible = "nuvoton,npcx-espi-taf";
reg = <0x4000a000 0x2000>;
status = "disabled";
};
};
};
soc-if {

View file

@ -255,6 +255,11 @@
buffer-tx-size = <128>;
shi-cs-wui =<&wui_io53>;
};
espi0: espi@4000a000 {
rx-plsize = <64>;
tx-plsize = <16>;
};
};
soc-id {

View file

@ -283,6 +283,11 @@
buffer-tx-size = <128>;
shi-cs-wui =<&wui_io53>;
};
espi0: espi@4000a000 {
rx-plsize = <64>;
tx-plsize = <16>;
};
};
soc-id {

View file

@ -0,0 +1,60 @@
# Copyright (c) 2023 Nuvoton Technology Corporation.
# SPDX-License-Identifier: Apache-2.0
description: |
The target flash devices accessed by Nuvoton eSPI TAF controller.
Representation:
espi_taf: espitaf@4000a000 {
compatible = "nuvoton,npcx-espi-taf";
reg = <0x4000a000 0x2000>;
mapped-addr = <0x68000000>;
max-read-sz = "NPCX_ESPI_TAF_MAX_READ_REQ_64B";
erase-sz = "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB";
#address-cells = <1>;
#size-cells = <1>;
status = "okay";
};
compatible: "nuvoton,npcx-espi-taf"
include: [espi-controller.yaml, pinctrl-device.yaml]
properties:
mapped-addr:
type: int
description: |
Mapped memory address of direct read access for flash.
required: true
erase-sz:
type: string
required: true
description: |
Erase block size of target flash. The default was 4KB Erase Block Size.
All Intel platforms require support for at least 4 KB Erase Block Size.
default: "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB"
enum:
- "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB"
- "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_32KB"
- "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_64KB"
- "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_128KB"
max-read-sz:
type: string
required: true
description: |
Maximum read request size of flash access channel. The default was 64 bytes.
This value is recommended in datasheet.
default: "NPCX_ESPI_TAF_MAX_READ_REQ_64B"
enum:
- "NPCX_ESPI_TAF_MAX_READ_REQ_64B"
- "NPCX_ESPI_TAF_MAX_READ_REQ_128B"
- "NPCX_ESPI_TAF_MAX_READ_REQ_256B"
- "NPCX_ESPI_TAF_MAX_READ_REQ_512B"
- "NPCX_ESPI_TAF_MAX_READ_REQ_1024B"
- "NPCX_ESPI_TAF_MAX_READ_REQ_2048B"
- "NPCX_ESPI_TAF_MAX_READ_REQ_4096B"

View file

@ -30,3 +30,13 @@ properties:
For example the WUI mapping on NPCX7 would be
espi-rst-wui = <&wui_cr_sin1>;
rx-plsize:
type: int
required: true
description: The maximum receive channel payload size.
tx-plsize:
type: int
required: true
description: The maximum transmit channel payload size.

View file

@ -145,6 +145,8 @@ 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);
typedef int (*espi_saf_api_flash_unsuccess)(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,
@ -158,6 +160,7 @@ __subsystem struct espi_saf_driver_api {
espi_saf_api_flash_read flash_read;
espi_saf_api_flash_write flash_write;
espi_saf_api_flash_erase flash_erase;
espi_saf_api_flash_unsuccess flash_unsuccess;
espi_saf_api_manage_callback manage_callback;
};
@ -383,6 +386,35 @@ static inline int z_impl_espi_saf_flash_erase(const struct device *dev,
return api->flash_erase(dev, pckt);
}
/**
* @brief Response unsuccessful completion for slave attached flash.
*
* This routines provides an interface to response that transaction is
* invalid and return unsuccessful completion from target to controller.
*
* @param dev Pointer to the device structure for the driver instance.
* @param pckt Address of the representation of 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_unsuccess(const struct device *dev,
struct espi_saf_packet *pckt);
static inline int z_impl_espi_saf_flash_unsuccess(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_unsuccess) {
return -ENOTSUP;
}
return api->flash_unsuccess(dev, pckt);
}
/**
* Callback model
*

View file

@ -27,4 +27,12 @@
((reg) = ((reg) & (~(((1 << (f_size))-1) << (f_pos)))) \
| ((value) << (f_pos)))
#define GET_FIELD_POS(field) \
_GET_FIELD_POS_(FIELD_POS(field))
#define _GET_FIELD_POS_(f_ops) f_ops
#define GET_FIELD_SZ(field) \
_GET_FIELD_SZ_(FIELD_SIZE(field))
#define _GET_FIELD_SZ_(f_ops) f_ops
#endif /* _NUVOTON_NPCX_REG_ACCESS_H */

View file

@ -625,14 +625,35 @@ struct espi_reg {
volatile uint32_t reserved8[11];
/* 0x3FC: OOB Channel Control used in 'direct' mode */
volatile uint32_t OOBCTL_DIRECT;
/* 0x400 - 443: Flash Receive Buffer 0-16 */
volatile uint32_t FLASHRXBUF[17];
volatile uint32_t reserved9[15];
/* 0x480 - 497: Flash Transmit Buffer 0-5 */
volatile uint32_t FLASHTXBUF[6];
volatile uint32_t reserved10[25];
/* 0x400 - 443: Flash Receive Buffer 0-17 */
volatile uint32_t FLASHRXBUF[18];
volatile uint32_t reserved9[14];
/* 0x480 - 497: Flash Transmit Buffer 0-16 */
volatile uint32_t FLASHTXBUF[17];
volatile uint32_t reserved10[14];
/* 0x4FC: Flash Channel Control used in 'direct' mode */
volatile uint32_t FLASHCTL_DIRECT;
volatile uint32_t reserved12[64];
/* 0x600 - 63F */
volatile uint32_t FLASH_PRTR_BADDR[16];
/* 0x640 - 67F */
volatile uint32_t FLASH_PRTR_HADDR[16];
/* 0x680 - 6BF */
volatile uint32_t FLASH_RGN_TAG_OVR[16];
volatile uint32_t reserved13[80];
/* 0x800 */
volatile uint32_t FLASH_RPMC_CFG_1;
/* 0x804 */
volatile uint32_t FLASH_RPMC_CFG_2;
/* 0x808 */
volatile uint32_t RMAP_FLASH_OFFS;
/* 0x80C */
volatile uint32_t RMAP_DST_BASE;
/* 0x810 */
volatile uint32_t RMAP_WIN_SIZE;
/* 0x814 */
volatile uint32_t FLASHBASE;
volatile uint32_t reserved14[58];
};
/* eSPI register fields */
@ -648,6 +669,7 @@ struct espi_reg {
#define NPCX_ESPICFG_HCHANS_FIELD FIELD(4, 4)
#define NPCX_ESPICFG_IOMODE_FIELD FIELD(8, 2)
#define NPCX_ESPICFG_MAXFREQ_FIELD FIELD(10, 3)
#define NPCX_ESPICFG_FLCHANMODE 16
#define NPCX_ESPICFG_PCCHN_SUPP 24
#define NPCX_ESPICFG_VWCHN_SUPP 25
#define NPCX_ESPICFG_OOBCHN_SUPP 26
@ -657,7 +679,7 @@ struct espi_reg {
#define NPCX_ESPIIE_BERRIE 2
#define NPCX_ESPIIE_OOBRXIE 3
#define NPCX_ESPIIE_FLASHRXIE 4
#define NPCX_ESPIIE_SFLASHRDIE 5
#define NPCX_ESPIIE_FLNACSIE 5
#define NPCX_ESPIIE_PERACCIE 6
#define NPCX_ESPIIE_DFRDIE 7
#define NPCX_ESPIIE_VWUPDIE 8
@ -675,6 +697,7 @@ struct espi_reg {
#define NPCX_ESPIWE_BERRWE 2
#define NPCX_ESPIWE_OOBRXWE 3
#define NPCX_ESPIWE_FLASHRXWE 4
#define NPCX_ESPIWE_FLNACSWE 5
#define NPCX_ESPIWE_PERACCWE 6
#define NPCX_ESPIWE_DFRDWE 7
#define NPCX_ESPIWE_VWUPDWE 8
@ -686,6 +709,7 @@ struct espi_reg {
#define NPCX_ESPISTS_BERR 2
#define NPCX_ESPISTS_OOBRX 3
#define NPCX_ESPISTS_FLASHRX 4
#define NPCX_ESPISTS_FLNACS 5
#define NPCX_ESPISTS_PERACC 6
#define NPCX_ESPISTS_DFRD 7
#define NPCX_ESPISTS_VWUPD 8
@ -700,6 +724,14 @@ struct espi_reg {
#define NPCX_ESPISTS_BMBURSTERR 22
#define NPCX_ESPISTS_BMBURSTDONE 23
#define NPCX_ESPISTS_ESPIRST_LVL 24
#define NPCX_VWSWIRQ_IRQ_NUM FIELD(0, 7)
#define NPCX_VWSWIRQ_IRQ_LVL 7
#define NPCX_VWSWIRQ_INDEX FIELD(8, 7)
#define NPCX_VWSWIRQ_INDEX_EN 15
#define NPCX_VWSWIRQ_DIRTY 16
#define NPCX_VWSWIRQ_ENPLTRST 17
#define NPCX_VWSWIRQ_ENCDRST 19
#define NPCX_VWSWIRQ_EDGE_IRQ 28
#define NPCX_VWEVMS_WIRE FIELD(0, 4)
#define NPCX_VWEVMS_VALID FIELD(4, 4)
#define NPCX_VWEVMS_IE 18
@ -716,6 +748,9 @@ struct espi_reg {
#define NPCX_FLASHCFG_FLASHBLERSSIZE FIELD(7, 3)
#define NPCX_FLASHCFG_FLASHPLSIZE FIELD(10, 3)
#define NPCX_FLASHCFG_FLASHREQSIZE FIELD(13, 3)
#define NPCX_FLASHCFG_FLCAPA FIELD(24, 2)
#define NPCX_FLASHCFG_TRGFLEBLKSIZE FIELD(16, 8)
#define NPCX_FLASHCFG_FLREQSUP FIELD(0, 3)
#define NPCX_FLASHCTL_FLASH_NP_FREE 0
#define NPCX_FLASHCTL_FLASH_TX_AVAIL 1
#define NPCX_FLASHCTL_STRPHDR 2
@ -725,10 +760,21 @@ struct espi_reg {
#define NPCX_FLASHCTL_CRCEN 14
#define NPCX_FLASHCTL_CHKSUMSEL 15
#define NPCX_FLASHCTL_AMTEN 16
#define NPCX_FLASHCTL_SAF_AUTO_READ 18
#define NPCX_FLASHCTL_AUTO_RD_DIS_CTL 19
#define NPCX_FLASHCTL_BLK_FLASH_NP_FREE 20
#define NPCX_FLASHBASE_FLBASE_ADDR FIELD(12, 15)
#define NPCX_FLASH_PRTR_BADDR FIELD(12, 15)
#define NPCX_FRGN_WPR 29
#define SAF_PROT_LCK 31
#define NPCX_FRGN_RPR 30
#define NPCX_FLASH_PRTR_HADDR FIELD(12, 15)
#define NPCX_FLASH_TAG_OVR_RPR FIELD(16, 16)
#define NPCX_FLASH_TAG_OVR_WPR FIELD(0, 16)
#define NPCX_ONLY_ESPI_REG1_UNLOCK_REG2 0x55
#define NPCX_ONLY_ESPI_REG1_LOCK_REG2 0
#define NPCX_ONLY_ESPI_REG2_TRANS_END_CONFIG 4
/*
* Mobile System Wake-Up Control (MSWC) device registers
*/

View file

@ -62,7 +62,7 @@ NPCX_REG_OFFSET_CHECK(twd_reg, TWMWD, 0x00e);
NPCX_REG_OFFSET_CHECK(twd_reg, WDCP, 0x010);
/* ESPI register structure check */
NPCX_REG_SIZE_CHECK(espi_reg, 0x500);
NPCX_REG_SIZE_CHECK(espi_reg, 0x900);
NPCX_REG_OFFSET_CHECK(espi_reg, FLASHCFG, 0x034);
NPCX_REG_OFFSET_CHECK(espi_reg, NPCX_ONLY_ESPI_REG1, 0x0f0);
NPCX_REG_OFFSET_CHECK(espi_reg, VWEVMS, 0x140);

View file

@ -0,0 +1,151 @@
/*
* Copyright (c) 2023 Nuvoton Technology Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _NUVOTON_NPCX_SOC_ESPI_TAF_H_
#define _NUVOTON_NPCX_SOC_ESPI_TAF_H_
#include <zephyr/device.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Transmit buffer for eSPI TAF transaction on NPCX */
/* +-------------+--------------+--------------+---------------+ */
/* | Byte 3 | Byte 2 | Byte 1 | Byte 0 | */
/* +-------------+--------------+--------------+---------------+ */
/* | Length | Tag |Length | Type | PKT_LEN | */
/* | [7:0] | |[11:8] | | | */
/* +-------------+--------------+--------------+---------------+ */
/* | Data 3 | Data 2 | Data 1 | Data 0 | */
/* +-------------+--------------+--------------+---------------+ */
/* | Data 7 | Data 6 | Data 5 | Data 4 | */
/* +-------------+--------------+--------------+---------------+ */
/* | ... | ... | ... | ... | */
/* +-------------+--------------+--------------+---------------+ */
/* | Data 63 | Data 62 | Data 61 | Data 60 | */
/* +-------------+--------------+--------------+---------------+ */
/* PKT_LEN holds the sum of header (Type, Tag and Length) length */
/* and data length */
/*
* NPCX_TAF_CMP_HEADER_LEN is the preamble length of Type, Length
* and Tag (i.e. byte 1~byte 3) for flash access completion packet
* on NPCX
*/
#define NPCX_TAF_CMP_HEADER_LEN 3
/* Successful Completion Without Data */
#define CYC_SCS_CMP_WITHOUT_DATA 0x06
/* Successful middle Completion With Data */
#define CYC_SCS_CMP_WITH_DATA_MIDDLE 0x09
/* Successful first Completion With Data */
#define CYC_SCS_CMP_WITH_DATA_FIRST 0x0B
/* Successful last Completion With Data */
#define CYC_SCS_CMP_WITH_DATA_LAST 0x0D
/* Successful only Completion With Data */
#define CYC_SCS_CMP_WITH_DATA_ONLY 0x0F
/* Unsuccessful Completion Without Data */
#define CYC_UNSCS_CMP_WITHOUT_DATA 0x08
/* Unsuccessful Last Completion Without Data */
#define CYC_UNSCS_CMP_WITHOUT_DATA_LAST 0x0C
/* Unsuccessful Only Completion Without Data */
#define CYC_UNSCS_CMP_WITHOUT_DATA_ONLY 0x0E
/* Timeout for checking transmit buffer available and no completion was sent */
#define NPCX_FLASH_CHK_TIMEOUT 10000
/* Clear RSTBUFHEADS, FLASH_ACC_TX_AVAIL, and FLASH_ACC_NP_FREE */
#define NPCX_FLASHCTL_ACCESS_MASK (~(BIT(NPCX_FLASHCTL_RSTBUFHEADS) | \
BIT(NPCX_FLASHCTL_FLASH_NP_FREE) | \
BIT(NPCX_FLASHCTL_FLASH_TX_AVAIL)))
/* Flash Sharing Capability Support */
#define NPCX_FLASH_SHARING_CAP_SUPP_CAF 0
#define NPCX_FLASH_SHARING_CAP_SUPP_TAF 2
#define NPCX_FLASH_SHARING_CAP_SUPP_TAF_AND_CAF 3
enum NPCX_ESPI_TAF_REQ {
NPCX_ESPI_TAF_REQ_READ,
NPCX_ESPI_TAF_REQ_WRITE,
NPCX_ESPI_TAF_REQ_ERASE,
NPCX_ESPI_TAF_REQ_RPMC_OP1,
NPCX_ESPI_TAF_REQ_RPMC_OP2,
NPCX_ESPI_TAF_REQ_UNKNOWN,
};
/* NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB is default */
enum NPCX_ESPI_TAF_ERASE_BLOCK_SIZE {
NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_1KB,
NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_2KB,
NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB,
NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_8KB,
NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_16KB,
NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_32KB,
NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_64KB,
NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_128KB,
};
/* NPCX_ESPI_TAF_MAX_READ_REQ_64B is default */
enum NPCX_ESPI_TAF_MAX_READ_REQ {
NPCX_ESPI_TAF_MAX_READ_REQ_64B = 1,
NPCX_ESPI_TAF_MAX_READ_REQ_128B,
NPCX_ESPI_TAF_MAX_READ_REQ_256B,
NPCX_ESPI_TAF_MAX_READ_REQ_512B,
NPCX_ESPI_TAF_MAX_READ_REQ_1024B,
NPCX_ESPI_TAF_MAX_READ_REQ_2048B,
NPCX_ESPI_TAF_MAX_READ_REQ_4096B,
};
/*
* The configurations of SPI flash are set in FIU module.
* Thus, eSPI TAF driver of NPCX does not need additional hardware configuarations.
* Therefore, define an empty structure here to comply with espi_saf.h
*/
struct espi_saf_hw_cfg {
};
struct espi_saf_pr {
uint32_t start;
uint32_t end;
uint16_t override_r;
uint16_t override_w;
uint8_t master_bm_we;
uint8_t master_bm_rd;
uint8_t pr_num;
uint8_t flags;
};
struct espi_saf_protection {
size_t nregions;
const struct espi_saf_pr *pregions;
};
struct espi_taf_npcx_pckt {
uint8_t tag;
uint8_t *data;
};
struct espi_taf_pckt {
uint8_t type;
uint8_t tag;
uint32_t addr;
uint16_t len;
uint32_t src[16];
};
struct npcx_taf_head {
uint8_t pkt_len;
uint8_t type;
uint8_t tag_hlen;
uint8_t llen;
};
#ifdef __cplusplus
}
#endif
#endif

View file

@ -14,6 +14,10 @@ config NUM_IRQS
config CORTEX_M_SYSTICK
default !NPCX_ITIM_TIMER
config ESPI_TAF_NPCX
default y
depends on ESPI_SAF
source "soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.npcx4*"
endif # SOC_SERIES_NPCX4

View file

@ -53,6 +53,7 @@
#include <reg/reg_def.h>
#include <soc_dt.h>
#include <soc_clock.h>
#include <soc_espi_taf.h>
#include <soc_pins.h>
#include <soc_power.h>