Merge "platform: msm_shared: RPMB Write performance enhancement"
diff --git a/platform/msm_shared/include/mmc_sdhci.h b/platform/msm_shared/include/mmc_sdhci.h
index 6ef404b..54f09ee 100644
--- a/platform/msm_shared/include/mmc_sdhci.h
+++ b/platform/msm_shared/include/mmc_sdhci.h
@@ -89,6 +89,7 @@
 #define MMC_EXT_CSD_RST_N_FUNC                    162
 #define MMC_EXT_MMC_BUS_WIDTH                     183
 #define MMC_EXT_MMC_HS_TIMING                     185
+#define MMC_EXT_CSD_REV                           192
 #define MMC_DEVICE_TYPE                           196
 #define MMC_EXT_MMC_DRV_STRENGTH                  197
 #define MMC_EXT_HC_WP_GRP_SIZE                    221
@@ -102,6 +103,7 @@
 #define MMC_ERASE_TIMEOUT_MULT                    223
 #define MMC_HC_ERASE_GRP_SIZE                     224
 #define MMC_PARTITION_CONFIG                      179
+#define MMC_EXT_CSD_EN_RPMB_REL_WR                166 //emmc 5.1 and above
 
 /* Values for ext csd fields */
 #define MMC_HS_TIMING                             0x1
diff --git a/platform/msm_shared/include/rpmb.h b/platform/msm_shared/include/rpmb.h
index 6cd7ecd..f954dfb 100644
--- a/platform/msm_shared/include/rpmb.h
+++ b/platform/msm_shared/include/rpmb.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -147,15 +147,15 @@
 int write_device_info_rpmb(void *info, uint32_t sz);
 
 /* Function Prototypes */
-int rpmb_write_emmc(struct mmc_device *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
+int rpmb_write_emmc(struct mmc_device *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t rel_wr_count, uint32_t *resp_buf, uint32_t *resp_len);
 int rpmb_read_emmc(struct mmc_device *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
-int rpmb_write_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
+int rpmb_write_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t rel_wr_count, uint32_t *resp_buf, uint32_t *resp_len);
 int rpmb_read_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
 
 /* APIs exposed to applications */
 int rpmb_init();
 int rpmb_uninit();
-int rpmb_write(uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
+int rpmb_write(uint32_t *req_buf, uint32_t blk_cnt, uint32_t rel_wr_count, uint32_t *resp_buf, uint32_t *resp_len);
 int rpmb_read(uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
 struct rpmb_init_info *rpmb_get_init_info();
 int rpmb_get_app_handle();
diff --git a/platform/msm_shared/include/sdhci.h b/platform/msm_shared/include/sdhci.h
index c0b484d..64fb2b0 100644
--- a/platform/msm_shared/include/sdhci.h
+++ b/platform/msm_shared/include/sdhci.h
@@ -102,6 +102,7 @@
 	uint64_t cmd_timeout;   /* Command timeout in us */
 	bool write_flag;        /* Write flag, for reliable write cases */
 	struct mmc_data data;   /* Data pointer */
+	uint8_t rel_write;      /* Reliable write enable flag */
 };
 
 /*
diff --git a/platform/msm_shared/rpmb/rpmb.c b/platform/msm_shared/rpmb/rpmb.c
index 36bacab..29d72e3 100644
--- a/platform/msm_shared/rpmb/rpmb.c
+++ b/platform/msm_shared/rpmb/rpmb.c
@@ -50,7 +50,30 @@
 	{
 		struct mmc_device *mmc_dev = (struct mmc_device *) dev;
 		info.size = mmc_dev->card.rpmb_size / RPMB_MIN_BLK_SZ;
-		info.rel_wr_count = mmc_dev->card.rel_wr_count;
+		if (mmc_dev->card.ext_csd[MMC_EXT_CSD_REV] < 8)
+		{
+			dprintf(SPEW, "EMMC Version < 5.1\n");
+			info.rel_wr_count = mmc_dev->card.rel_wr_count;
+		}
+		else
+		{
+			if (mmc_dev->card.ext_csd[MMC_EXT_CSD_EN_RPMB_REL_WR] == 0)
+			{
+				dprintf(SPEW, "EMMC Version >= 5.1 EN_RPMB_REL_WR = 0\n");
+				// according to emmc version 5.1 and above if EN_RPMB_REL_WR in extended
+				// csd is not set the maximum number of frames that can be reliably written
+				// to emmc would be 2
+				info.rel_wr_count = 2;
+			}
+			else
+			{
+				dprintf(SPEW, "EMMC Version >= 5.1 EN_RPMB_REL_WR = 1\n");
+				// according to emmc version 5.1 and above if EN_RPMB_REL_WR in extended
+				// csd is set the maximum number of frames that can be reliably written
+				// to emmc would be 32
+				info.rel_wr_count = 32;
+			}
+		}
 		info.dev_type  = EMMC_RPMB;
 	}
 	else
@@ -105,12 +128,12 @@
 		return rpmb_read_ufs(dev, req, req_len, resp, resp_len);
 }
 
-int rpmb_write(uint32_t *req, uint32_t req_len, uint32_t *resp, uint32_t *resp_len)
+int rpmb_write(uint32_t *req, uint32_t req_len, uint32_t rel_wr_count, uint32_t *resp, uint32_t *resp_len)
 {
 	if (platform_boot_dev_isemmc())
-		return rpmb_write_emmc(dev, req, req_len, resp, resp_len);
+		return rpmb_write_emmc(dev, req, req_len, rel_wr_count, resp, resp_len);
 	else
-		return rpmb_write_ufs(dev, req, req_len, resp, resp_len);
+		return rpmb_write_ufs(dev, req, req_len, rel_wr_count, resp, resp_len);
 }
 
 /* This API calls into TZ app to read device_info */
diff --git a/platform/msm_shared/rpmb/rpmb_emmc.c b/platform/msm_shared/rpmb/rpmb_emmc.c
index 2bfa545..3b00e09 100644
--- a/platform/msm_shared/rpmb/rpmb_emmc.c
+++ b/platform/msm_shared/rpmb/rpmb_emmc.c
@@ -47,17 +47,36 @@
 	.requestresponse[1] = READ_RESULT_FLAG,
 };
 
-int rpmb_write_emmc(struct mmc_device *dev,uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len)
+int rpmb_write_emmc(struct mmc_device *dev,uint32_t *req_buf, uint32_t blk_cnt, uint32_t rel_wr_count, uint32_t *resp_buf, uint32_t *resp_len)
 {
-	uint32_t i;
+	uint32_t i, num_trans;
 	int ret = 0;
 	struct mmc_command cmd[3] = {{0},{0},{0}};
 	struct rpmb_frame *result = (struct rpmb_frame *)resp_buf;
 
-	for (i = 0; i < blk_cnt; i++)
+	dprintf(INFO, "rpmb write command called with blk_cnt: 0x%x\n", blk_cnt);
+	if (rel_wr_count == 0x2)
+	{
+		// if reliable write count reported by secure app is 2 then we can
+		// send two half sectors in one transaction. So overall number of
+		// transactions would be total block count by 2.
+		num_trans = blk_cnt / 2;
+	}
+	else if(rel_wr_count == 0x1)
+	{
+		num_trans = blk_cnt; // rel_rw_count = 1 for emmc 5.0 and below
+	}
+	else
+	{
+		dprintf(CRITICAL, "Reliable write count > 2 is not supported\n");
+		return -1;
+	}
+
+	for (i = 0; i < num_trans; i++)
 	{
 #if DEBUG_RPMB
-		dump_rpmb_frame((uint8_t *)req_buf, "request");
+		for(uint8_t j = 0; j < rel_wr_count; j++)
+			dump_rpmb_frame((uint8_t *)req_buf + (j * 512), "request");
 #endif
 
 		/* CMD25 program data packet */
@@ -69,8 +88,16 @@
 		cmd[0].trans_mode = SDHCI_MMC_WRITE;
 		cmd[0].data_present = 0x1;
 		cmd[0].data.data_ptr = (void *)req_buf;
-		cmd[0].data.num_blocks = RPMB_MIN_BLK_CNT;
-
+		if (rel_wr_count == 0x1)
+		{
+			cmd[0].rel_write = 0;
+			cmd[0].data.num_blocks = RPMB_MIN_BLK_CNT;
+		}
+		else if(rel_wr_count == 0x2)
+		{
+			cmd[0].rel_write = 1;
+			cmd[0].data.num_blocks = 0x2;
+		}
 		/* CMD25 Result Register Read Request Packet */
 		cmd[1].write_flag = false;
 		cmd[1].cmd_index = CMD25_WRITE_MULTIPLE_BLOCK;
@@ -101,6 +128,9 @@
 			break;
 		}
 
+#if DEBUG_RPMB
+		dump_rpmb_frame((uint8_t *)resp_buf, "response");
+#endif
 		if (result->result[0] == 0x80)
 		{
 			dprintf(CRITICAL, "Max write counter reached: \n");
@@ -112,12 +142,11 @@
 			dprintf(CRITICAL, "%s\n", str_err[result->result[1]]);
 			break;
 		}
+		if (rel_wr_count == 0x1)
+			req_buf = (uint32_t*) ((uint8_t*)req_buf + (RPMB_BLK_SIZE));
+		else if(rel_wr_count == 0x2)
+			req_buf = (uint32_t*) ((uint8_t*)req_buf + (RPMB_BLK_SIZE * 0x2));
 
-		req_buf = (uint32_t*) ((uint8_t*)req_buf + RPMB_BLK_SIZE);
-
-#if DEBUG_RPMB
-		dump_rpmb_frame((uint8_t *)resp_buf, "response");
-#endif
 	}
 	*resp_len = RPMB_MIN_BLK_CNT * RPMB_BLK_SIZE;
 
diff --git a/platform/msm_shared/rpmb/rpmb_listener.c b/platform/msm_shared/rpmb/rpmb_listener.c
index 7cf0b79..c9623e2 100644
--- a/platform/msm_shared/rpmb/rpmb_listener.c
+++ b/platform/msm_shared/rpmb/rpmb_listener.c
@@ -67,6 +67,8 @@
 	uint32_t num_sectors;
 	uint32_t req_buff_len;
 	uint32_t req_buff_offset;
+	uint32_t version;
+	uint32_t rel_wr_count;
 }__PACKED;
 
 struct tz_rpmb_rw_resp
@@ -75,6 +77,7 @@
 	int32_t  status;
 	uint32_t res_buff_len;
 	uint32_t res_buff_offset;
+	uint32_t version;
 }__PACKED;
 
 typedef int (*ListenerCallback)(void*, uint32_t);
@@ -113,14 +116,16 @@
 		case TZ_CM_CMD_RPMB_READ:
 #if DEBUG_RPMB
 			dprintf(INFO, "Read Request received\n");
+			dprintf(INFO, "READ: RPMB_REL_RW_COUNT 0x%x\n", req_p->rel_wr_count);
 #endif
 			resp_p->status = rpmb_read(req_buf, req_p->num_sectors, resp_buf, &resp_p->res_buff_len);
 			break;
 		case TZ_CM_CMD_RPMB_WRITE:
 #if DEBUG_RPMB
 			dprintf(INFO, "Write Request received\n");
+			dprintf(INFO, "WRITE: RPMB_REL_RW_COUNT 0x%x\n", req_p->rel_wr_count);
 #endif
-			resp_p->status = rpmb_write(req_buf, req_p->num_sectors, resp_buf, &resp_p->res_buff_len);
+			resp_p->status = rpmb_write(req_buf, req_p->num_sectors, req_p->rel_wr_count, resp_buf, &resp_p->res_buff_len);
 			break;
 		default:
 			dprintf(CRITICAL, "Unsupported request command request: %u\n", req_p->cmd_id);
@@ -174,7 +179,7 @@
 
 	rpmb_listener.service_name = "RPMB system services";
 	rpmb_listener.id           =  RPMB_LSTNR_ID;
-	rpmb_listener.sb_size      = 20 * 1024;
+	rpmb_listener.sb_size      = 25 * 1024;
 	rpmb_listener.service_cmd_handler = rpmb_cmd_handler;
 
 	ret = qseecom_register_listener(&rpmb_listener);
diff --git a/platform/msm_shared/rpmb/rpmb_ufs.c b/platform/msm_shared/rpmb/rpmb_ufs.c
index 3cc4d91..17cfc56 100644
--- a/platform/msm_shared/rpmb/rpmb_ufs.c
+++ b/platform/msm_shared/rpmb/rpmb_ufs.c
@@ -36,6 +36,18 @@
 #include <endian.h>
 #include <arch/defines.h>
 
+static const char *str_err[] =
+{
+	"Operation Ok",
+	"General failure",
+	"Authentication error (MAC comparison not matching, MAC calculation failure)",
+	"Counter failure (counters not matching in comparison, counter incrementing failure)",
+	"Address failure (address out of range, wrong address alignment)",
+	"Write failure (data/counter/result write failure)",
+	"Read failure (data/counter/result read failure)",
+	"Authentication Key not yet programmed",
+};
+
 static struct rpmb_frame read_result_reg =
 {
 	.requestresponse[1] = READ_RESULT_FLAG,
@@ -71,8 +83,8 @@
 		return -UFS_FAILURE;
 	}
 #ifdef DEBUG_RPMB
-	dprintf(SPEW, "rpmb_read: req_buf: 0x%x blk_count: 0x%x\n", *req_buf, blk_cnt);
-	dprintf(INFO, "rpmb_read: bytes_to_transfer: 0x%x blks_to_transfer: 0x%x\n",
+	dprintf(INFO, "rpmb_read: req_buf: 0x%x blk_count: 0x%x\n", *req_buf, blk_cnt);
+	dprintf(INFO, "rpmb_read: bytes_to_transfer: 0x%llx blks_to_transfer: 0x%x\n",
                    bytes_to_transfer, blks_to_transfer);
 #endif
 	// send the request
@@ -138,15 +150,18 @@
 		dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
 		return -UFS_FAILURE;
 	}
+	// invalidate response buffer before reading response as this is part of request
+	// buffer overwritten
+	arch_clean_invalidate_cache_range((addr_t) resp_buf, RPMB_FRAME_SIZE);
 #ifdef DEBUG_RPMB
-	dprintf(SPEW, "Sending RPMB Read response complete\n");
+	dprintf(INFO, "Sending RPMB Read response complete\n");
 	dump_rpmb_frame((uint8_t *)resp_buf, "response");
 #endif
 	*resp_len = bytes_to_transfer;
 	return UFS_SUCCESS;
 }
 
-int rpmb_write_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len)
+int rpmb_write_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t rel_wr_count, uint32_t *resp_buf, uint32_t *resp_len)
 {
 	// validate input parameters
 	ASSERT(req_buf);
@@ -156,12 +171,14 @@
 	STACKBUF_DMA_ALIGN(cdb, sizeof(struct scsi_sec_protocol_cdb));
 	struct scsi_req_build_type   req_upiu;
 	struct scsi_sec_protocol_cdb *cdb_out_param, *cdb_in_param;
+	struct rpmb_frame *result = (struct rpmb_frame *)resp_buf;
 	uint32_t                     blks_remaining;
 	uint32_t                     blks_to_transfer;
 	uint64_t                     bytes_to_transfer;
 	uint64_t                     max_size;
 	uint32_t                     result_frame_bytes = RPMB_FRAME_SIZE;
 	uint32_t                     i;
+	uint32_t                     num_trans;
 
 	blks_remaining    = blk_cnt;
 	blks_to_transfer  = blks_remaining;
@@ -176,13 +193,31 @@
 	}
 #ifdef DEBUG_RPMB
 	dprintf(INFO, "%s: req_buf: 0x%x blk_count: 0x%x\n", __func__,*req_buf, blk_cnt);
-	dprintf(INFO, "%s: bytes_to_transfer: 0x%x blks_to_transfer: 0x%x\n", __func__
-                   bytes_to_transfer, blk_cnt);
-	dump_rpmb_frame((uint8_t *)req_buf, "request");
+	dprintf(INFO, "%s: bytes_to_transfer: 0x%llx blks_to_transfer: 0x%x\n", __func__, bytes_to_transfer, blk_cnt);
 #endif
-
-	for (i = 0; i < blk_cnt; i++)
+	if (bytes_to_transfer <= (rel_wr_count * RPMB_FRAME_SIZE))
 	{
+		num_trans = 1;
+	}
+	else
+	{
+		// send uptop rel_wr_count number of frames in one shot + anything pending
+		num_trans = blk_cnt/rel_wr_count;
+		if (num_trans % rel_wr_count) // if anymore frames still pending
+			num_trans++;
+	}
+	for (i = 0; i < num_trans; i++)
+	{
+		if ((num_trans - i) == 1) // last loop or one and only loop
+		{
+			// last loop will contain a max of rel_wr_count number of frames or less
+			bytes_to_transfer = RPMB_FRAME_SIZE * blks_remaining;
+		}
+		else
+		{
+			bytes_to_transfer = RPMB_FRAME_SIZE * rel_wr_count;
+		}
+
 		// send the request
 		cdb_out_param = (struct scsi_sec_protocol_cdb*) cdb;
 		memset(cdb_out_param, 0, sizeof(struct scsi_sec_protocol_cdb));
@@ -190,6 +225,44 @@
 		cdb_out_param->opcode                = SCSI_CMD_SECPROT_OUT;
 		cdb_out_param->cdb1                  = SCSI_SEC_PROT;
 		cdb_out_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
+		cdb_out_param->alloc_tlen            = BE32(bytes_to_transfer);
+
+		// Flush CDB to memory
+		dsb();
+		arch_clean_invalidate_cache_range((addr_t) cdb_out_param, sizeof(struct scsi_sec_protocol_cdb));
+
+		memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
+
+		req_upiu.cdb              = (addr_t) cdb_out_param;
+		req_upiu.data_buffer_addr = (addr_t) req_buf;
+		req_upiu.data_len         = bytes_to_transfer;
+		req_upiu.flags            = UPIU_FLAGS_WRITE;
+		req_upiu.lun              = UFS_WLUN_RPMB;
+		req_upiu.dd               = UTRD_TARGET_TO_SYSTEM;
+
+#ifdef DEBUG_RPMB
+		dprintf(INFO, "Sending RPMB write request: Start\n");
+		for(uint8_t j = 0; j < (bytes_to_transfer/RPMB_FRAME_SIZE); j++)
+		{
+			dprintf(INFO, "request buffer address: %p\n", (req_buf + (j * RPMB_FRAME_SIZE)));
+			dump_rpmb_frame((uint8_t *)req_buf + (j * RPMB_FRAME_SIZE), "request");
+		}
+#endif
+		if (ucs_do_scsi_cmd(dev, &req_upiu))
+		{
+			dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
+			return -UFS_FAILURE;
+		}
+#ifdef DEBUG_RPMB
+		dprintf(INFO, "Sending RPMB write request: Done\n");
+#endif
+		// Result Read
+		cdb_out_param = (struct scsi_sec_protocol_cdb*) cdb;
+		memset(cdb_out_param, 0, sizeof(struct scsi_sec_protocol_cdb));
+
+		cdb_out_param->opcode                = SCSI_CMD_SECPROT_OUT;
+		cdb_out_param->cdb1                  = SCSI_SEC_PROT;
+		cdb_out_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
 		cdb_out_param->alloc_tlen            = BE32(RPMB_FRAME_SIZE);
 
 		// Flush CDB to memory
@@ -199,39 +272,6 @@
 		memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
 
 		req_upiu.cdb              = (addr_t) cdb_out_param;
-		req_upiu.data_buffer_addr = (addr_t) req_buf;
-		req_upiu.data_len         = RPMB_FRAME_SIZE;
-		req_upiu.flags            = UPIU_FLAGS_WRITE;
-		req_upiu.lun              = UFS_WLUN_RPMB;
-		req_upiu.dd               = UTRD_TARGET_TO_SYSTEM;
-
-#ifdef DEBUG_RPMB
-		dprintf(INFO, "Sending RPMB write request: Start\n");
-#endif
-		if (ucs_do_scsi_cmd(dev, &req_upiu))
-		{
-			dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
-			return -UFS_FAILURE;
-		}
-#ifdef DEBUG_RPMB
-		dprintf(INFO, "Sending RPMB write request: Done\n");
-#endif
-		// Result Read
-		cdb_in_param = (struct scsi_sec_protocol_cdb*) cdb;
-		memset(cdb_in_param, 0, sizeof(struct scsi_sec_protocol_cdb));
-
-		cdb_in_param->opcode                = SCSI_CMD_SECPROT_OUT;
-		cdb_in_param->cdb1                  = SCSI_SEC_PROT;
-		cdb_in_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
-		cdb_in_param->alloc_tlen            = BE32(RPMB_FRAME_SIZE);
-
-		// Flush CDB to memory
-		dsb();
-		arch_clean_invalidate_cache_range((addr_t) cdb_in_param, sizeof(struct scsi_sec_protocol_cdb));
-
-		memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
-
-		req_upiu.cdb              = (addr_t) cdb_in_param;
 		req_upiu.data_buffer_addr = (addr_t) &read_result_reg ;
 		req_upiu.data_len         = result_frame_bytes;
 		req_upiu.flags            = UPIU_FLAGS_WRITE;
@@ -247,7 +287,7 @@
 			return -UFS_FAILURE;
 		}
 #ifdef DEBUG_RPMB
-		dprintf(SPEW, "Sending RPMB Result Read Register: Done\n");
+		dprintf(INFO, "Sending RPMB Result Read Register: Done\n");
 #endif
 
 		// Retrieve verification result
@@ -280,12 +320,34 @@
 			dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
 			return -UFS_FAILURE;
 		}
+		// invalidate response buffer before reading response as this is part of request
+		// buffer overwritten
+		arch_clean_invalidate_cache_range((addr_t) resp_buf, result_frame_bytes);
 #ifdef DEBUG_RPMB
-		dprintf(SPEW, "Sending RPMB Response for Result Read Register: Done\n");
+		dprintf(INFO, "Sending RPMB Response for Result Read Register: Done\n");
 		dump_rpmb_frame((uint8_t *)resp_buf, "response");
 #endif
 
-		req_buf = (uint32_t*) ((uint8_t*)req_buf + RPMB_BLK_SIZE);
+		if (result->result[0] == 0x80)
+		{
+			dprintf(CRITICAL, "Max write counter reached: \n");
+			break;
+		}
+
+		if (result->result[1])
+		{
+			dprintf(CRITICAL, "UFS RPMB write error: %s\n", str_err[result->result[1]]);
+			break;
+		}
+		if ((num_trans - i) == 1)
+			continue; // last frame no need to increment
+		else
+		{
+			req_buf = (uint32_t*) ((uint8_t*)req_buf + (RPMB_BLK_SIZE * rel_wr_count));
+			// If more than 1 transaction, then until the last loop, we will be transfering
+			// rel_wr_count number of half sections in one transaction
+			blks_remaining = blks_remaining - rel_wr_count;
+		}
 	}
 
 	*resp_len = RPMB_MIN_BLK_CNT * RPMB_BLK_SIZE;
diff --git a/platform/msm_shared/sdhci.c b/platform/msm_shared/sdhci.c
index 72126bf..bfab9f1 100644
--- a/platform/msm_shared/sdhci.c
+++ b/platform/msm_shared/sdhci.c
@@ -863,7 +863,7 @@
 		/* Enable auto cmd23 or cmd12 for multi block transfer
 		 * based on what command card supports
 		 */
-		if (cmd->data.num_blocks > 1) {
+		if ((cmd->data.num_blocks > 1) && !cmd->rel_write) {
 			if (cmd->cmd23_support) {
 				trans_mode |= SDHCI_TRANS_MULTI | SDHCI_AUTO_CMD23_EN | SDHCI_BLK_CNT_EN;
 				REG_WRITE32(host, cmd->data.num_blocks, SDHCI_ARG2_REG);
@@ -871,6 +871,9 @@
 			else
 				trans_mode |= SDHCI_TRANS_MULTI | SDHCI_AUTO_CMD12_EN | SDHCI_BLK_CNT_EN;
 		}
+		else if ((cmd->data.num_blocks > 1) && cmd->rel_write) {
+			trans_mode |= SDHCI_TRANS_MULTI | SDHCI_BLK_CNT_EN;
+		}
 	}
 
 	/* Write to transfer mode register */