diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 452782b..e185c9d 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -99,6 +99,7 @@ struct mmc_blk_data {
 #define MMC_BLK_CMD23	(1 << 0)	/* Can do SET_BLOCK_COUNT for multiblock */
 #define MMC_BLK_REL_WR	(1 << 1)	/* MMC Reliable write support */
 #define MMC_BLK_PACKED_CMD	(1 << 2)	/* MMC packed command support */
+#define MMC_BLK_SUSPENDED	(1 << 3)	/* MMC block device suspended */
 
 	unsigned int	usage;
 	unsigned int	read_only;
@@ -109,6 +110,8 @@ struct mmc_blk_data {
 #define MMC_BLK_WRITE		BIT(1)
 #define MMC_BLK_DISCARD		BIT(2)
 #define MMC_BLK_SECDISCARD	BIT(3)
+#define MMC_BLK_RPMB		BIT(4)
+#define MMC_BLK_USER		BIT(5)
 
 	/*
 	 * Only set in main mmc_blk_data associated
@@ -149,6 +152,9 @@ static inline void mmc_blk_clear_packed(struct mmc_queue_req *mqrq)
 	packed->blocks = 0;
 }
 
+static int mmc_rpmb_req_process(struct mmc_blk_data *,
+		struct mmc_ioc_rpmb_req *);
+
 static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 {
 	struct mmc_blk_data *md;
@@ -1025,6 +1031,118 @@ static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
 	md->reset_done &= ~type;
 }
 
+static int mmc_rpmb_req_process(struct mmc_blk_data *md,
+		struct mmc_ioc_rpmb_req *req)
+{
+	struct mmc_core_rpmb_req rpmb_req;
+	struct mmc_card *card = NULL;
+	int ret;
+
+	if (!md || !req)
+		return -EINVAL;
+
+	if (!(md->flags & MMC_BLK_CMD23) ||
+			(md->part_type != EXT_CSD_PART_CONFIG_ACC_RPMB))
+		return -EOPNOTSUPP;
+
+	card = md->queue.card;
+	if (!card || !mmc_card_mmc(card) || !card->ext_csd.rpmb_size)
+		return -ENODEV;
+
+	memset(&rpmb_req, 0, sizeof(struct mmc_core_rpmb_req));
+	rpmb_req.req = req;
+	/* check request */
+	ret = mmc_rpmb_pre_frame(&rpmb_req, card);
+	if (ret) {
+		pr_err("%s: prepare frame failed\n", mmc_hostname(card->host));
+		return ret;
+	}
+
+	mmc_claim_host(card->host);
+
+	if (md->flags & MMC_BLK_SUSPENDED) {
+		pr_warn("%s: MMC block device is already suspended\n",
+				mmc_hostname(card->host));
+		ret = -EPERM;
+		goto out;
+	}
+
+	/* wait for background operation finished */
+	mmc_stop_bkops(card);
+
+	/*
+	 * before start, let's change to RPMB partition first
+	 */
+	ret = mmc_blk_part_switch(card, md);
+	if (ret) {
+		pr_err("%s: Invalid RPMB partition switch (%d)!\n",
+				mmc_hostname(card->host), ret);
+		/*
+		 * In case partition is not in user data area, make
+		 * a force partition switch.
+		 * we need reset eMMC card at here
+		 */
+		ret = mmc_blk_reset(md, card->host, MMC_BLK_RPMB);
+		if (!ret)
+			mmc_blk_reset_success(md, MMC_BLK_RPMB);
+		else
+			pr_err("%s: eMMC card reset failed (%d)\n",
+					mmc_hostname(card->host), ret);
+		goto out;
+	}
+
+	ret = mmc_rpmb_partition_ops(&rpmb_req, card);
+	if (ret)
+		pr_err("%s: failed (%d) to handle RPMB request type (%d)!\n",
+				mmc_hostname(card->host), ret, req->type);
+out:
+	mmc_release_host(card->host);
+	mmc_rpmb_post_frame(&rpmb_req);
+	return ret;
+}
+
+int mmc_access_rpmb(struct mmc_queue *mq)
+{
+	struct mmc_blk_data *md = mq->data;
+	/*
+	 * If this is a RPMB partition access, return ture
+	 */
+	if (md && md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB)
+		return true;
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(mmc_access_rpmb);
+
+int mmc_rpmb_req_handle(struct device *emmc, struct mmc_ioc_rpmb_req *req)
+{
+	int ret = 0;
+	struct gendisk *disk    = NULL;
+	struct mmc_blk_data *md = NULL;
+
+	if (!emmc || !req)
+		return -EINVAL;
+
+	disk = dev_to_disk(emmc);
+	if (!disk) {
+		pr_err("%s: NO eMMC disk found. Try it later\n",
+				__func__);
+		return -ENODEV;
+	}
+
+	md = mmc_blk_get(disk);
+	if (!md) {
+		pr_err("%s: NO eMMC block data. Try it later\n",
+				__func__);
+		return -ENODEV;
+	}
+	ret = mmc_rpmb_req_process(md, req);
+	mmc_blk_put(md);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mmc_rpmb_req_handle);
+
 static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 {
 	struct mmc_blk_data *md = mq->data;
@@ -2016,11 +2134,16 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 
 	ret = mmc_blk_part_switch(card, md);
 	if (ret) {
-		if (req) {
-			blk_end_request_all(req, -EIO);
+		pr_err("%s: switch part failed. Try to reset eMMC\n",
+				mmc_hostname(card->host));
+		if (mmc_blk_reset(md, card->host, MMC_BLK_USER)) {
+			if (req)
+				blk_end_request_all(req, -EIO);
+			ret = 0;
+			goto out;
 		}
-		ret = 0;
-		goto out;
+		pr_info("%s: Reset eMMC success\n", mmc_hostname(card->host));
+		mmc_blk_reset_success(md, MMC_BLK_USER);
 	}
 
 	mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
@@ -2501,6 +2624,19 @@ static int _mmc_blk_suspend(struct mmc_card *card)
 		mmc_queue_suspend(&md->queue);
 		list_for_each_entry(part_md, &md->part, part) {
 			mmc_queue_suspend(&part_md->queue);
+			if (part_md->part_type ==
+				EXT_CSD_PART_CONFIG_ACC_RPMB) {
+				/*
+				 * RPMB partition is accessed by API directly.
+				 * Driver need to set a flag when suspending
+				 * MMC block device to notify API that the
+				 * accessing of RPMB partition needs to be
+				 * stopped
+				 */
+				mmc_claim_host(card->host);
+				part_md->flags |= MMC_BLK_SUSPENDED;
+				mmc_release_host(card->host);
+			}
 		}
 	}
 	return 0;
@@ -2531,6 +2667,18 @@ static int mmc_blk_resume(struct mmc_card *card)
 		mmc_queue_resume(&md->queue);
 		list_for_each_entry(part_md, &md->part, part) {
 			mmc_queue_resume(&part_md->queue);
+			if (part_md->part_type ==
+					EXT_CSD_PART_CONFIG_ACC_RPMB) {
+				/*
+				 * RPMB partition is accessed by API directly.
+				 * Driver need to clear MMC_BLK_SUSPENDED flag
+				 * to make sure the next RPMB partition access
+				 * request won't be blocked
+				 */
+				mmc_claim_host(card->host);
+				part_md->flags &= ~MMC_BLK_SUSPENDED;
+				mmc_release_host(card->host);
+			}
 		}
 	}
 	return 0;
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 3e049c1..6ceede0 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -38,7 +38,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
 		return BLKPREP_KILL;
 	}
 
-	if (mq && mmc_card_removed(mq->card))
+	if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq)))
 		return BLKPREP_KILL;
 
 	req->cmd_flags |= REQ_DONTPREP;
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 5752d50..3bbd4e6 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -73,4 +73,5 @@ extern void mmc_queue_bounce_post(struct mmc_queue_req *);
 extern int mmc_packed_init(struct mmc_queue *, struct mmc_card *);
 extern void mmc_packed_clean(struct mmc_queue *);
 
+extern int mmc_access_rpmb(struct mmc_queue *);
 #endif
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 793c6f7..59766ec 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -553,6 +553,9 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 		 * RPMB regions are defined in multiples of 128K.
 		 */
 		card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT];
+		card->ext_csd.rpmb_size = 128 *
+			card->ext_csd.raw_rpmb_size_mult;
+		card->ext_csd.rpmb_size <<= 2; /* Unit: half sector */
 		if (ext_csd[EXT_CSD_RPMB_MULT] && mmc_host_cmd23(card->host)) {
 			mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17,
 				EXT_CSD_PART_CONFIG_ACC_RPMB,
@@ -604,6 +607,18 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 		card->ext_csd.data_sector_size = 512;
 	}
 
+	/*
+	 * If use legacy relaible write, then the blk counts must not
+	 * big than the relaible write sectors
+	 */
+	if (!(card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN)) {
+		if (card->ext_csd.rel_sectors < RPMB_AVALIABLE_SECTORS)
+			card->rpmb_max_req = card->ext_csd.rel_sectors;
+		else
+			card->rpmb_max_req = RPMB_AVALIABLE_SECTORS;
+	} else
+		card->rpmb_max_req = RPMB_AVALIABLE_SECTORS;
+
 out:
 	return err;
 }
@@ -710,6 +725,7 @@ MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
 MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
 MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
 MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
+MMC_DEV_ATTR(rpmb_size, "%d\n", card->ext_csd.rpmb_size);
 
 static struct attribute *mmc_std_attrs[] = {
 	&dev_attr_cid.attr,
@@ -728,6 +744,7 @@ static struct attribute *mmc_std_attrs[] = {
 	&dev_attr_enhanced_area_size.attr,
 	&dev_attr_raw_rpmb_size_mult.attr,
 	&dev_attr_rel_sectors.attr,
+	&dev_attr_rpmb_size.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(mmc_std);
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index f51b5ba..8d9f921 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -655,3 +655,399 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
 
 	return 0;
 }
+
+static int mmc_rpmb_send_command(struct mmc_card *card, u8 *buf, __u16 blks,
+		__u16 type, u8 req_type)
+{
+	struct mmc_request mrq = {NULL};
+	struct mmc_command cmd = {0};
+	struct mmc_command sbc = {0};
+	struct mmc_data data = {0};
+	struct scatterlist sg;
+	u8 *transfer_buf = NULL;
+
+	mrq.sbc = &sbc;
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+	mrq.stop = NULL;
+	transfer_buf = kzalloc(512 * blks, GFP_KERNEL);
+	if (!transfer_buf)
+		return -ENOMEM;
+
+	/*
+	 * set CMD23
+	 */
+	sbc.opcode = MMC_SET_BLOCK_COUNT;
+	sbc.arg = blks;
+	if ((req_type == RPMB_REQ) && type == RPMB_WRITE_DATA)
+		sbc.arg |= 1 << 31;
+	sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+	/*
+	 * set CMD25/18
+	 */
+	sg_init_one(&sg, transfer_buf, 512 * blks);
+	if (req_type == RPMB_REQ) {
+		cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
+		sg_copy_from_buffer(&sg, 1, buf, 512 * blks);
+		data.flags |= MMC_DATA_WRITE;
+	} else {
+		cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
+		data.flags |= MMC_DATA_READ;
+	}
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+	data.blksz = 512;
+	data.blocks = blks;
+	data.sg = &sg;
+	data.sg_len = 1;
+
+	mmc_set_data_timeout(&data, card);
+
+	mmc_wait_for_req(card->host, &mrq);
+
+	if (req_type != RPMB_REQ)
+		sg_copy_to_buffer(&sg, 1, buf, 512 * blks);
+
+	kfree(transfer_buf);
+
+	if (cmd.error)
+		return cmd.error;
+	if (data.error)
+		return data.error;
+	return 0;
+}
+
+void mmc_rpmb_post_frame(struct mmc_core_rpmb_req *rpmb_req)
+{
+	int i;
+	struct mmc_ioc_rpmb_req *p_req;
+	__u8 *buf_frame;
+
+	if (!rpmb_req || !rpmb_req->ready)
+		return;
+
+	p_req = rpmb_req->req;
+	buf_frame = rpmb_req->frame;
+
+	if (!p_req || !buf_frame)
+		return;
+	/*
+	 * Regarding to the check rules, here is the post
+	 * rules
+	 * All will return result.
+	 * GET_WRITE_COUNTER:
+	 *              must: write counter, nonce
+	 *              optional: MAC
+	 * WRITE_DATA:
+	 *              must: MAC, write counter
+	 * READ_DATA:
+	 *              must: nonce, data
+	 *              optional: MAC
+	 * PROGRAM_KEY:
+	 *              must: Nothing
+	 *
+	 * Except READ_DATA, all of these operations only need to parse
+	 * one frame. READ_DATA needs blks frames to get DATA
+	 */
+
+	memcpy(p_req->result, buf_frame + RPMB_RES_BEG, 2);
+	*p_req->result = be16_to_cpup(p_req->result);
+
+	if (p_req->type == RPMB_PROGRAM_KEY)
+		goto out;
+
+	if (p_req->type == RPMB_GET_WRITE_COUNTER ||
+			p_req->type == RPMB_WRITE_DATA) {
+		memcpy(p_req->wc, buf_frame + RPMB_WCOUNTER_BEG, 4);
+		*p_req->wc = be32_to_cpup(p_req->wc);
+	}
+
+	if (p_req->type == RPMB_GET_WRITE_COUNTER ||
+			p_req->type == RPMB_READ_DATA) {
+		/* nonce copy */
+		memcpy(p_req->nonce, buf_frame + RPMB_NONCE_BEG, 16);
+	}
+	/*
+	 * Take MAC within the last package
+	 */
+	if (p_req->type == RPMB_READ_DATA) {
+		__u8 *data = p_req->data;
+		for (i = 0; i < p_req->blk_cnt; i++) {
+			memcpy(data, buf_frame + i * 512 + RPMB_DATA_BEG, 256);
+			data += 256;
+		}
+		/*
+		 * MAC stored in the last package
+		 */
+		if (p_req->mac) {
+			i--;
+			memcpy(p_req->mac, buf_frame + i * 512 + RPMB_MAC_BEG,
+					32);
+		}
+	} else if (p_req->mac)
+		memcpy(p_req->mac, buf_frame + RPMB_MAC_BEG, 32);
+out:
+	kfree(buf_frame);
+	rpmb_req->frame = NULL;
+	return;
+}
+EXPORT_SYMBOL_GPL(mmc_rpmb_post_frame);
+
+static int mmc_rpmb_request_check(struct mmc_card *card,
+		struct mmc_ioc_rpmb_req *p_req)
+{
+	/*
+	 * Some paramter is a must for the operation. Different
+	 * operation expect different paramters. Below code is
+	 * used for checking this.
+	 *
+	 * All operations will need result.
+	 * GET_WRITE_COUNTER:
+	 *              must: write counter, nonce
+	 *              optional: MAC
+	 * WRITE_DATA:
+	 *              must: MAC, data, write counter
+	 * READ_DATA:
+	 *              must: nonce, data
+	 *              optional: MAC
+	 * PROGRAM_KEY:
+	 *              must: MAC
+	 *
+	 * So here, we only check the 'must' paramters
+	 */
+	if (!p_req->result) {
+		pr_err("%s: Type %d has NULL pointer for result\n",
+				mmc_hostname(card->host), p_req->type);
+		return -EINVAL;
+	}
+
+	if (p_req->type == RPMB_GET_WRITE_COUNTER) {
+		if (!p_req->nonce || !p_req->wc) {
+			pr_err("%s: Type %d has NULL pointer for nonce/wc\n",
+					mmc_hostname(card->host), p_req->type);
+			return -EINVAL;
+		}
+		/*
+		 * used to allocate frame
+		 */
+		p_req->blk_cnt = 1;
+	} else if (p_req->type == RPMB_WRITE_DATA ||
+			p_req->type == RPMB_READ_DATA) {
+		if ((__u32)(p_req->addr + p_req->blk_cnt) >
+				card->ext_csd.rpmb_size) {
+			pr_err("%s Type %d: beyond the RPMB partition rang addr %d, blk_cnt %d, rpmb_size %d\n",
+					mmc_hostname(card->host),
+					p_req->type,
+					p_req->addr,
+					p_req->blk_cnt,
+					card->ext_csd.rpmb_size);
+			/*
+			 * Not return error here since we want device to handle
+			 * such errors
+			 */
+		}
+		if (p_req->blk_cnt == 0) {
+			pr_err("%s: Type %d has zero block count\n",
+					mmc_hostname(card->host),
+					p_req->blk_cnt);
+			return -EINVAL;
+		} else if (p_req->blk_cnt > card->rpmb_max_req) {
+			pr_err("%s: Type %d has invalid block count, cannot large than %d\n",
+					mmc_hostname(card->host),
+					p_req->blk_cnt,
+					card->rpmb_max_req);
+			return -EINVAL;
+		}
+		if (!p_req->data) {
+			pr_err("%s: Type %d has NULL pointer for data\n",
+					mmc_hostname(card->host), p_req->type);
+			return -EINVAL;
+		}
+		if (p_req->type == RPMB_WRITE_DATA) {
+			if (!p_req->wc || !p_req->mac) {
+				pr_err("%s: Type %d has NULL pointer for write counter/MAC\n",
+						mmc_hostname(card->host),
+						p_req->type);
+				return -EINVAL;
+			}
+		} else {
+			if (!p_req->nonce) {
+				pr_err("%s: Type %d has NULL pointer for nonce\n",
+						mmc_hostname(card->host),
+						p_req->type);
+				return -EINVAL;
+			}
+		}
+	} else
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
+/*
+ * prepare the request of RPMB frame
+ * RPMB frame is MSB first
+ * convert needed bytes
+ * return how many frames will be prepared
+ */
+int mmc_rpmb_pre_frame(struct mmc_core_rpmb_req *rpmb_req,
+		struct mmc_card *card)
+{
+	int i, ret;
+	struct mmc_ioc_rpmb_req *p_req;
+	__u8 *buf_frame;
+	__u16 blk_cnt, addr, type;
+	__u32 w_counter;
+
+	if (!rpmb_req || !card)
+		return -EINVAL;
+
+	p_req = rpmb_req->req;
+	if (!p_req) {
+		pr_err("%s: mmc_ioc_rpmb_req is NULL. Wrong parameter\n",
+				mmc_hostname(card->host));
+		return -EINVAL;
+	}
+
+	/*
+	 * make sure these two items are clear
+	 */
+	rpmb_req->ready = 0;
+	rpmb_req->frame = NULL;
+
+	ret = mmc_rpmb_request_check(card, p_req);
+	if (ret)
+		return ret;
+
+	buf_frame = kzalloc(512 * p_req->blk_cnt, GFP_KERNEL);
+	if (!buf_frame) {
+		pr_err("%s: cannot allocate frame for type %d\n",
+				mmc_hostname(card->host), p_req->type);
+		return -ENOMEM;
+	}
+
+	type = cpu_to_be16p(&p_req->type);
+	if (p_req->type == RPMB_GET_WRITE_COUNTER ||
+			p_req->type == RPMB_READ_DATA) {
+		/*
+		 * One package prepared
+		 * This request needs Nonce and type
+		 * If is data read, then also need addr
+		 */
+		memcpy(buf_frame + RPMB_TYPE_BEG, &type, 2);
+		if (p_req->type == RPMB_READ_DATA) {
+			addr = cpu_to_be16p(&p_req->addr);
+			memcpy(buf_frame + RPMB_ADDR_BEG, &addr, 2);
+		}
+		/* convert Nonce code */
+		memcpy(buf_frame + RPMB_NONCE_BEG, p_req->nonce, 16);
+	} else if (p_req->type == RPMB_WRITE_DATA) {
+		__u8 *data = p_req->data;
+		/*
+		 * multiple package prepared
+		 * This request nees blk_cnt, addr, write_counter,
+		 * data and mac
+		 */
+		blk_cnt = cpu_to_be16p(&p_req->blk_cnt);
+		addr = cpu_to_be16p(&p_req->addr);
+		w_counter = cpu_to_be32p(p_req->wc);
+		for (i = 0; i < p_req->blk_cnt; i++) {
+			memcpy(buf_frame + i * 512 + RPMB_TYPE_BEG,
+					&type, 2);
+			memcpy(buf_frame + i * 512 + RPMB_BLKS_BEG,
+					&blk_cnt, 2);
+			memcpy(buf_frame + i * 512 + RPMB_ADDR_BEG,
+					&addr, 2);
+			memcpy(buf_frame + i * 512 + RPMB_WCOUNTER_BEG,
+					&w_counter, 4);
+			memcpy(buf_frame + i * 512 + RPMB_DATA_BEG,
+					data, 256);
+			data += 256;
+		}
+		/* convert MAC code */
+		memcpy(buf_frame + 512 * (i - 1) + RPMB_MAC_BEG,
+				p_req->mac, 32);
+	} else {
+		pr_err("%s: We shouldn't be here\n", mmc_hostname(card->host));
+		kfree(buf_frame);
+		return -EINVAL;
+	}
+	rpmb_req->ready = 1;
+	rpmb_req->frame = buf_frame;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mmc_rpmb_pre_frame);
+
+int mmc_rpmb_partition_ops(struct mmc_core_rpmb_req *rpmb_req,
+		struct mmc_card *card)
+{
+	int err = 0;
+	struct mmc_ioc_rpmb_req *p_req;
+	__u16 type, blks;
+	__u8 *buf_frame;
+
+	if (!rpmb_req || !card)
+		return -EINVAL;
+
+	p_req = rpmb_req->req;
+	buf_frame = rpmb_req->frame;
+
+	if (!p_req || !rpmb_req->ready || !buf_frame) {
+		pr_err("%s: mmc_ioc_rpmb_req is not prepared\n",
+				mmc_hostname(card->host));
+		return -EINVAL;
+	}
+
+	type = p_req->type;
+	blks = p_req->blk_cnt;
+
+	/*
+	 * STEP 1: send request to RPMB partition
+	 */
+	if (type == RPMB_WRITE_DATA)
+		err = mmc_rpmb_send_command(card, buf_frame, blks,
+				type, RPMB_REQ);
+	else
+		err = mmc_rpmb_send_command(card, buf_frame, 1, type, RPMB_REQ);
+
+	if (err) {
+		pr_err("%s: request write counter failed (%d)\n",
+				mmc_hostname(card->host), err);
+		goto out;
+	}
+
+	memset(buf_frame, 0, 512 * blks);
+	/*
+	 * STEP 2: check write result
+	 * Only for WRITE_DATA or Program key
+	 */
+	if (type == RPMB_WRITE_DATA) {
+		buf_frame[RPMB_TYPE_BEG + 1] = RPMB_RESULT_READ;
+		err = mmc_rpmb_send_command(card, buf_frame, 1,
+				RPMB_RESULT_READ, RPMB_REQ);
+		if (err) {
+			pr_err("%s: request write counter failed (%d)\n",
+					mmc_hostname(card->host), err);
+			goto out;
+		}
+	}
+
+	/*
+	 * STEP 3: get response from RPMB partition
+	 */
+
+	if (type == RPMB_READ_DATA)
+		err = mmc_rpmb_send_command(card, buf_frame,
+				blks, type, RPMB_RESP);
+	else
+		err = mmc_rpmb_send_command(card, buf_frame,
+				1, type, RPMB_RESP);
+	if (err) {
+		pr_err("%s: response write counter failed (%d)\n",
+				mmc_hostname(card->host), err);
+	}
+out:
+	return err;
+}
+EXPORT_SYMBOL_GPL(mmc_rpmb_partition_ops);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index d424b9d..971404a 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -83,6 +83,7 @@ struct mmc_ext_csd {
 	unsigned int		hpi_cmd;		/* cmd used as HPI */
 	bool			bkops;		/* background support bit */
 	bool			bkops_en;	/* background enable bit */
+	unsigned int		rpmb_size;		/* Units: half sector */
 	unsigned int            data_sector_size;       /* 512 bytes or 4KB */
 	unsigned int            data_tag_unit_size;     /* DATA TAG UNIT size */
 	unsigned int		boot_ro_lock;		/* ro lock support */
@@ -304,6 +305,7 @@ struct mmc_card {
 	struct dentry		*debugfs_root;
 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
 	unsigned int    nr_parts;
+	unsigned int		rpmb_max_req;
 };
 
 /*
@@ -529,4 +531,7 @@ extern void mmc_unregister_driver(struct mmc_driver *);
 extern void mmc_fixup_device(struct mmc_card *card,
 			     const struct mmc_fixup *table);
 
+extern int mmc_rpmb_req_handle(struct device *emmc,
+		struct mmc_ioc_rpmb_req *req);
+
 #endif /* LINUX_MMC_CARD_H */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index f206e29..5e07733 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -10,6 +10,8 @@
 
 #include <linux/interrupt.h>
 #include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/mmc/ioctl.h>
 
 struct request;
 struct mmc_data;
@@ -137,6 +139,34 @@ struct mmc_request {
 	struct mmc_host		*host;
 };
 
+/*
+ * RPMB frame structure for MMC core stack
+ */
+struct mmc_core_rpmb_req {
+	struct mmc_ioc_rpmb_req *req;
+	__u8 *frame;
+	bool ready;
+};
+
+#define RPMB_PROGRAM_KEY       1       /* Program RPMB Authentication Key */
+#define RPMB_GET_WRITE_COUNTER 2       /* Read RPMB write counter */
+#define RPMB_WRITE_DATA		3	/* Write data to RPMB partition */
+#define RPMB_READ_DATA         4       /* Read data from RPMB partition */
+#define RPMB_RESULT_READ       5       /* Read result request */
+#define RPMB_REQ               1       /* RPMB request mark */
+#define RPMB_RESP              (1 << 1)/* RPMB response mark */
+#define RPMB_AVALIABLE_SECTORS 8       /* 4K page size */
+
+#define RPMB_TYPE_BEG          510
+#define RPMB_RES_BEG           508
+#define RPMB_BLKS_BEG          506
+#define RPMB_ADDR_BEG          504
+#define RPMB_WCOUNTER_BEG      500
+
+#define RPMB_NONCE_BEG         484
+#define RPMB_DATA_BEG          228
+#define RPMB_MAC_BEG           196
+
 struct mmc_card;
 struct mmc_async_req;
 
@@ -155,6 +185,10 @@ extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
 			bool, bool);
 extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
 extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
+extern int mmc_rpmb_partition_ops(struct mmc_core_rpmb_req *,
+		struct mmc_card *);
+extern int mmc_rpmb_pre_frame(struct mmc_core_rpmb_req *, struct mmc_card *);
+extern void mmc_rpmb_post_frame(struct mmc_core_rpmb_req *);
 
 #define MMC_ERASE_ARG		0x00000000
 #define MMC_SECURE_ERASE_ARG	0x80000000
diff --git a/include/uapi/linux/mmc/ioctl.h b/include/uapi/linux/mmc/ioctl.h
index 1f5e689..98ad956 100644
--- a/include/uapi/linux/mmc/ioctl.h
+++ b/include/uapi/linux/mmc/ioctl.h
@@ -47,6 +47,19 @@ struct mmc_ioc_cmd {
 
 #define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd)
 
+struct mmc_ioc_rpmb_req {
+	__u16 type;                     /* RPMB request type */
+	__u16 *result;                  /* response or request result */
+	__u16 blk_cnt;                  /* Number of blocks(half sector 256B) */
+	__u16 addr;                     /* data address */
+	__u32 *wc;                      /* write counter */
+	__u8 *nonce;                    /* Ramdom number */
+	__u8 *data;                     /* Buffer of the user data */
+	__u8 *mac;                      /* Message Authentication Code */
+};
+
+#define MMC_IOC_RPMB_REQ _IOWR(MMC_BLOCK_MAJOR, 1, struct mmc_ioc_rpmb_req)
+
 /*
  * Since this ioctl is only meant to enhance (and not replace) normal access
  * to the mmc bus device, an upper data transfer limit of MMC_IOC_MAX_BYTES
