drivers: espi: npcx: support espi taf rpmc request

This commit adds support for handling espi taf rpmc requests.

Signed-off-by: Tom Chang <CHChang19@nuvoton.com>
diff --git a/drivers/espi/Kconfig.npcx b/drivers/espi/Kconfig.npcx
index 884b5cd..94624c9 100644
--- a/drivers/espi/Kconfig.npcx
+++ b/drivers/espi/Kconfig.npcx
@@ -90,6 +90,13 @@
 	  This size is display how many group of slave attached flash protection
 	  region.
 
+config ESPI_TAF_NPCX_RPMC_SUPPORT
+	bool "eSPI TAF RPMC support"
+	depends on ESPI_TAF_NPCX
+	select FLASH_EX_OP_ENABLED
+	help
+	  This option enable the handler for eSPI TAF RPMC request.
+
 # The default value 'y' for the existing options if ESPI_NPCX is selected.
 if ESPI_NPCX
 
diff --git a/drivers/espi/espi_npcx.c b/drivers/espi/espi_npcx.c
index b134efa..28c88b7 100644
--- a/drivers/espi/espi_npcx.c
+++ b/drivers/espi/espi_npcx.c
@@ -402,8 +402,10 @@
 	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 == NPCX_ESPI_TAF_REQ_WRITE) {
+	/* Get written data if eSPI TAF write or RPMC OP1 */
+	if ((taf_pckt.type == NPCX_ESPI_TAF_REQ_WRITE) ||
+	    (IS_ENABLED(CONFIG_ESPI_TAF_NPCX_RPMC_SUPPORT) &&
+	     (taf_pckt.type == NPCX_ESPI_TAF_REQ_RPMC_OP1))) {
 		roundsize = DIV_ROUND_UP(taf_pckt.len, sizeof(uint32_t));
 		for (i = 0; i < roundsize; i++) {
 			taf_pckt.src[i] = inst->FLASHRXBUF[2 + i];
diff --git a/drivers/espi/espi_taf_npcx.c b/drivers/espi/espi_taf_npcx.c
index 7878df2..997c536 100644
--- a/drivers/espi/espi_taf_npcx.c
+++ b/drivers/espi/espi_taf_npcx.c
@@ -10,6 +10,9 @@
 #include <zephyr/drivers/espi.h>
 #include <zephyr/drivers/espi_saf.h>
 #include <zephyr/drivers/flash.h>
+#ifdef CONFIG_ESPI_TAF_NPCX_RPMC_SUPPORT
+#include <zephyr/drivers/flash/npcx_flash_api_ex.h>
+#endif
 #include <zephyr/kernel.h>
 #include <zephyr/logging/log.h>
 
@@ -31,8 +34,14 @@
 	uintptr_t rx_plsz;
 	enum NPCX_ESPI_TAF_ERASE_BLOCK_SIZE erase_sz;
 	enum NPCX_ESPI_TAF_MAX_READ_REQ max_rd_sz;
+#ifdef CONFIG_ESPI_TAF_NPCX_RPMC_SUPPORT
+	uint8_t rpmc_cnt_num;
+	uint8_t rpmc_op1_code;
+#endif
 };
 
+#define MAX_TX_PAYLOAD_SIZE DT_PROP(DT_INST_PARENT(0), tx_plsize)
+
 struct espi_taf_npcx_data {
 	sys_slist_t *callbacks;
 	const struct device *host_dev;
@@ -41,6 +50,7 @@
 	uint32_t address;
 	uint16_t length;
 	uint32_t src[16];
+	uint8_t read_buf[MAX_TX_PAYLOAD_SIZE];
 	struct k_work work;
 };
 
@@ -74,8 +84,9 @@
 	pckt->length = data_ptr->len;
 	pckt->taf_tag = data_ptr->tag;
 	pckt->address = data_ptr->addr;
-
-	if (data_ptr->type == NPCX_ESPI_TAF_REQ_WRITE) {
+	if ((data_ptr->type == NPCX_ESPI_TAF_REQ_WRITE) ||
+	    (IS_ENABLED(CONFIG_ESPI_TAF_NPCX_RPMC_SUPPORT) &&
+	     (data_ptr->type == NPCX_ESPI_TAF_REQ_RPMC_OP1))) {
 		memcpy(pckt->src, data_ptr->src, sizeof(pckt->src));
 	}
 }
@@ -322,7 +333,6 @@
 	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;
-	uint8_t read_buf[64];
 	int rc;
 
 	if (flash_req_size > target_max_size) {
@@ -352,14 +362,14 @@
 	}
 
 	do {
-		rc = flash_read(spi_dev, addr, &read_buf[0], len);
+		rc = flash_read(spi_dev, addr, npcx_espi_taf_data.read_buf, len);
 		if (rc) {
 			LOG_ERR("flash read fail 0x%x", rc);
 			return -EIO;
 		}
 
 		rc = taf_npcx_completion_handler(dev, cycle_type, taf_data_ptr->tag, len,
-						 (uint32_t *)&read_buf[0]);
+						 (uint32_t *)npcx_espi_taf_data.read_buf);
 		if (rc) {
 			LOG_ERR("espi taf completion handler fail");
 			return rc;
@@ -444,6 +454,73 @@
 	return 0;
 }
 
+#ifdef CONFIG_ESPI_TAF_NPCX_RPMC_SUPPORT
+static int espi_taf_npcx_rpmc_op1(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 = taf_data_ptr->data;
+	struct npcx_ex_ops_uma_in op_in = {
+		.opcode = ESPI_TAF_RPMC_OP1_CMD,
+		.tx_buf = data_ptr + 1,
+		.tx_count = (pckt->len) - 1,
+		.rx_count = 0,
+	};
+	int rc;
+
+	rc = flash_ex_op(spi_dev, FLASH_NPCX_EX_OP_EXEC_UMA, (uintptr_t)&op_in, NULL);
+	if (rc) {
+		LOG_ERR("flash RPMC OP1 fail");
+		return -EIO;
+	}
+
+	rc = taf_npcx_completion_handler(dev, CYC_SCS_CMP_WITHOUT_DATA, taf_data_ptr->tag, 0x0,
+					 NULL);
+	if (rc) {
+		LOG_ERR("espi taf completion handler fail");
+		return rc;
+	}
+
+	return 0;
+}
+
+static int espi_taf_npcx_rpmc_op2(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 dummy_byte = 0;
+	struct npcx_ex_ops_uma_in op_in = {
+		.opcode = ESPI_TAF_RPMC_OP2_CMD,
+		.tx_buf = &dummy_byte,
+		.tx_count = 1,
+		.rx_count = pckt->len,
+	};
+	struct npcx_ex_ops_uma_out op_out = {
+		.rx_buf = npcx_espi_taf_data.read_buf,
+	};
+
+	int rc;
+
+	if (pckt->len > MAX_TX_PAYLOAD_SIZE) {
+		LOG_ERR("Invalid size");
+		return -EINVAL;
+	}
+
+	rc = flash_ex_op(spi_dev, FLASH_NPCX_EX_OP_EXEC_UMA, (uintptr_t)&op_in, &op_out);
+	if (rc) {
+		LOG_ERR("flash RPMC OP2 fail");
+		return -EIO;
+	}
+
+	rc = taf_npcx_completion_handler(dev, CYC_SCS_CMP_WITH_DATA_ONLY, taf_data_ptr->tag,
+					 pckt->len, (uint32_t *)npcx_espi_taf_data.read_buf);
+	if (rc) {
+		LOG_ERR("espi taf completion handler fail");
+		return rc;
+	}
+
+	return 0;
+}
+#endif
+
 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;
@@ -470,7 +547,9 @@
 	pckt_taf.flash_addr = info->address;
 	pckt_taf.len = info->length;
 	taf_data.tag = info->taf_tag;
-	if (info->taf_type == NPCX_ESPI_TAF_REQ_WRITE) {
+	if ((info->taf_type == NPCX_ESPI_TAF_REQ_WRITE) ||
+	    (IS_ENABLED(CONFIG_ESPI_TAF_NPCX_RPMC_SUPPORT) &&
+	     (info->taf_type == NPCX_ESPI_TAF_REQ_RPMC_OP1))) {
 		taf_data.data = (uint8_t *)info->src;
 	} else {
 		taf_data.data = NULL;
@@ -489,6 +568,14 @@
 	case NPCX_ESPI_TAF_REQ_WRITE:
 		ret = espi_taf_npcx_flash_write(info->host_dev, &pckt_taf);
 		break;
+#ifdef CONFIG_ESPI_TAF_NPCX_RPMC_SUPPORT
+	case NPCX_ESPI_TAF_REQ_RPMC_OP1:
+		ret = espi_taf_npcx_rpmc_op1(info->host_dev, &pckt_taf);
+		break;
+	case NPCX_ESPI_TAF_REQ_RPMC_OP2:
+		ret = espi_taf_npcx_rpmc_op2(info->host_dev, &pckt_taf);
+		break;
+#endif
 	}
 
 	if (ret != 0) {
@@ -533,6 +620,21 @@
 		  config->max_rd_sz);
 	inst->FLASHBASE = config->mapped_addr;
 
+#ifdef CONFIG_ESPI_TAF_NPCX_RPMC_SUPPORT
+	uint8_t count_num = 0;
+
+	/* RPMC_CFG1_CNTR is 0-based number, e.g. 0 indicates that 1 counter is supported, 1
+	 * indicates 2 counters, etc.
+	 */
+	if (config->rpmc_cnt_num > 0) {
+		count_num = config->rpmc_cnt_num - 1;
+	}
+
+	SET_FIELD(inst->FLASH_RPMC_CFG_1, NPCX_FLASH_RPMC_CFG1_CNTR, count_num);
+	SET_FIELD(inst->FLASH_RPMC_CFG_1, NPCX_FLASH_RPMC_CFG1_OP1, config->rpmc_op1_code);
+	SET_FIELD(inst->FLASH_RPMC_CFG_1, NPCX_FLASH_RPMC_CFG1_TRGRPMCSUP, config->rpmc_cnt_num);
+#endif
+
 	return 0;
 }
 
@@ -549,6 +651,10 @@
 	.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),
+#ifdef CONFIG_ESPI_TAF_NPCX_RPMC_SUPPORT
+	.rpmc_cnt_num = DT_INST_PROP(0, rpmc_cntr),
+	.rpmc_op1_code = DT_INST_PROP(0, rpmc_op1_code),
+#endif
 };
 
 DEVICE_DT_INST_DEFINE(0, &espi_taf_npcx_init, NULL,
diff --git a/dts/bindings/espi/nuvoton,npcx-espi-taf.yaml b/dts/bindings/espi/nuvoton,npcx-espi-taf.yaml
index 115f8e5..8a065ab 100644
--- a/dts/bindings/espi/nuvoton,npcx-espi-taf.yaml
+++ b/dts/bindings/espi/nuvoton,npcx-espi-taf.yaml
@@ -58,3 +58,15 @@
       - "NPCX_ESPI_TAF_MAX_READ_REQ_1024B"
       - "NPCX_ESPI_TAF_MAX_READ_REQ_2048B"
       - "NPCX_ESPI_TAF_MAX_READ_REQ_4096B"
+
+  rpmc-cntr:
+    type: int
+    description: |
+      RPMC counter on RPMC flash devices.
+    default: 0
+
+  rpmc-op1-code:
+    type: int
+    description: |
+      RPMC OP1 opcode on RPMC flash devices.
+    default: 0
diff --git a/soc/nuvoton/npcx/common/reg/reg_def.h b/soc/nuvoton/npcx/common/reg/reg_def.h
index 915694b..9bbd37b 100644
--- a/soc/nuvoton/npcx/common/reg/reg_def.h
+++ b/soc/nuvoton/npcx/common/reg/reg_def.h
@@ -791,6 +791,9 @@
 #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_FLASH_RPMC_CFG1_CNTR        FIELD(0, 4)
+#define NPCX_FLASH_RPMC_CFG1_OP1         FIELD(4, 8)
+#define NPCX_FLASH_RPMC_CFG1_TRGRPMCSUP  FIELD(26, 6)
 #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
diff --git a/soc/nuvoton/npcx/common/soc_espi_taf.h b/soc/nuvoton/npcx/common/soc_espi_taf.h
index 90b98cb..f4a80a2 100644
--- a/soc/nuvoton/npcx/common/soc_espi_taf.h
+++ b/soc/nuvoton/npcx/common/soc_espi_taf.h
@@ -55,6 +55,11 @@
 /* Unsuccessful Only Completion Without Data */
 #define CYC_UNSCS_CMP_WITHOUT_DATA_ONLY            0x0E
 
+/* ESPI TAF RPMC OP1 instruction */
+#define ESPI_TAF_RPMC_OP1_CMD                      0x9B
+/* ESPI TAF RPMC OP2 instruction */
+#define ESPI_TAF_RPMC_OP2_CMD                      0x96
+
 /* Timeout for checking transmit buffer available and no completion was sent */
 #define NPCX_FLASH_CHK_TIMEOUT                     10000