platform: msm_shared: Add support for rpmb

Add support for rpmb listener, rpmb driver for emmc & ufs.

Change-Id: Iacfb2bd34d6ddc309f2c7f5422576fa253322f82
diff --git a/platform/msm_shared/include/rpmb.h b/platform/msm_shared/include/rpmb.h
index 8bbd985..6cd7ecd 100644
--- a/platform/msm_shared/include/rpmb.h
+++ b/platform/msm_shared/include/rpmb.h
@@ -26,6 +26,49 @@
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifndef _RPMB_H_
+#define _RPMB_H_
+
+#include <qseecom_lk_api.h>
+#include <mmc_sdhci.h>
+#include <ufs.h>
+#include <debug.h>
+
+#define RPMB_SECTOR_SIZE            256
+#define RPMB_LSTNR_ID               0x2000
+#define RPMB_BLK_SIZE               512
+#define RPMB_FRAME_SIZE             512
+#define RPMB_MIN_BLK_CNT            1
+#define RPMB_MIN_BLK_SZ             512
+
+enum app_commands
+{
+	CLIENT_CMD_READ_LK_DEVICE_STATE = 0,
+	CLIENT_CMD_LK_END_MILESTONE,
+	CLIENT_CMD_GET_VERSION,
+	CLIENT_CMD_WRITE_LK_DEVICE_STATE,
+};
+
+struct send_cmd_req
+{
+	uint32_t cmd_id;
+	uint32_t data;
+	uint32_t len;
+}__PACKED;
+
+struct send_cmd_rsp
+{
+	uint32_t cmd_id;
+	uint32_t data;
+	int32_t status;
+}__PACKED;
+
+enum device_type
+{
+	EMMC_RPMB = 3,
+	UFS_RPMB = 9,
+};
+
 /* RPMB request and response types */
 enum rpmb_rr_type {
 	KEY_PROVISION = 0x1,
@@ -62,9 +105,61 @@
 	uint8_t  keyMAC[32];
 	uint8_t  data[256];
 	uint8_t  nonce[16];
-	uint32_t writecounter;
-	uint16_t address;
-	uint16_t blockcount;
+	uint8_t writecounter[4];
+	uint8_t address[2];
+	uint8_t blockcount[2];
 	uint8_t  result[2];
-	uint16_t requestresponse;
+	uint8_t requestresponse[2];
 };
+
+struct rpmb_init_info
+{
+	uint32_t size;
+	uint32_t rel_wr_count;
+	uint32_t dev_type;
+};
+
+/* dump a given RPMB frame */
+static inline void dump_rpmb_frame(uint8_t *frame, const char *frame_type)
+{
+    int i;
+    char buf[512] = {0};
+    char *p = buf;
+
+    printf("Printing %s frame (in hex)\n", frame_type);
+    printf("________0__1__2__3__4__5__6__7__8__9__A__B__C__D__E__F__0__1__2__3__4__5__6__7__8__9__A__B__C__D__E__F\n");
+    for (i = 0; i < 512; i++) {
+        if (!(i % 32)) {
+            snprintf(p, 8, "| %2d | ", (i + 1) / 32);
+            p += 7;
+        }
+        snprintf(p, 4, "%.2x ", frame[i]);
+        p += 3;
+        if (((i + 1) % 32) == 0) {
+            printf("%s\n", buf);
+            p = buf;
+        }
+    }
+    printf("________F__E__D__C__B__A__9__8__7__6__5__4__3__2__1__0__F__E__D__C__B__A__9__8__7__6__5__4__3__2__1__0\n");
+}
+
+int read_device_info_rpmb(void *info, uint32_t sz);
+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_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_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_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();
+bool is_sec_app_loaded();
+int load_sec_app();
+int unload_sec_app();
+#endif
diff --git a/platform/msm_shared/include/rpmb_listener.h b/platform/msm_shared/include/rpmb_listener.h
new file mode 100644
index 0000000..a3bb3e5
--- /dev/null
+++ b/platform/msm_shared/include/rpmb_listener.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 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
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <qseecom_lk_api.h>
+#include <mmc_sdhci.h>
+#include <ufs.h>
+
+#define RPMB_LSTNR_ID               0x2000
+
+int rpmb_listener_start();
+int rpmb_listener_stop();
diff --git a/platform/msm_shared/rpmb/rpmb.c b/platform/msm_shared/rpmb/rpmb.c
new file mode 100644
index 0000000..de67c46
--- /dev/null
+++ b/platform/msm_shared/rpmb/rpmb.c
@@ -0,0 +1,251 @@
+/* Copyright (c) 2013-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
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <platform.h>
+#include <rpmb.h>
+#include <rpmb_listener.h>
+#include <mmc_sdhci.h>
+#include <boot_device.h>
+#include <debug.h>
+#include <target.h>
+
+static bool lksec_app_loaded;
+
+static void *dev;
+static int app_handle;
+struct rpmb_init_info info;
+
+int rpmb_init()
+{
+	int ret = 0;
+
+	dev = target_mmc_device();
+
+	/* 1. Initialize storage specific data */
+	if (platform_boot_dev_isemmc())
+	{
+		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;
+		info.dev_type  = EMMC_RPMB;
+	}
+	else
+	{
+		struct ufs_dev *ufs_dev = (struct ufs_dev *) dev;
+		ufs_rpmb_init(ufs_dev);
+		info.size = ufs_dev->rpmb_num_blocks;
+		info.rel_wr_count = ufs_dev->rpmb_rw_size;
+		info.dev_type  = UFS_RPMB;
+	}
+
+	/* Initialize Qseecom */
+	ret = qseecom_init();
+
+	if (ret < 0)
+	{
+		dprintf(CRITICAL, "Failed to initialize qseecom, error: %d\n", ret);
+		goto err;
+	}
+
+	/* Register & start the listener */
+	ret = rpmb_listener_start();
+	if (ret < 0)
+	{
+		dprintf(CRITICAL, "Error registering the handler\n");
+		goto err;
+	}
+
+	/* Start Qseecom */
+	ret = qseecom_tz_init();
+
+	if (ret < 0)
+	{
+		dprintf(CRITICAL, "Failed to start qseecom, error: %d\n", ret);
+		goto err;
+	}
+
+err:
+	return ret;
+}
+
+struct rpmb_init_info *rpmb_get_init_info()
+{
+	return &info;
+}
+
+int rpmb_read(uint32_t *req, uint32_t req_len, uint32_t *resp, uint32_t *resp_len)
+{
+	if (platform_boot_dev_isemmc())
+		return rpmb_read_emmc(dev, req, req_len, resp, resp_len);
+	else
+		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)
+{
+	if (platform_boot_dev_isemmc())
+		return rpmb_write_emmc(dev, req, req_len, resp, resp_len);
+	else
+		return rpmb_write_ufs(dev, req, req_len, resp, resp_len);
+}
+
+/* This API calls into TZ app to read device_info */
+int read_device_info_rpmb(void *info, uint32_t sz)
+{
+	int ret = 0;
+	struct send_cmd_req read_req = {0};
+	struct send_cmd_rsp read_rsp = {0};
+
+	/*
+	 * Load the sec app for first time
+	 */
+	if (!lksec_app_loaded)
+	{
+		if (load_sec_app() < 0)
+		{
+			dprintf(CRITICAL, "Failed to load App for rpmb\n");
+			ASSERT(0);
+		}
+		lksec_app_loaded = true;
+	}
+
+	read_req.cmd_id = CLIENT_CMD_READ_LK_DEVICE_STATE;
+	read_req.data   = (uint32_t) info;
+	read_req.len    = sz;
+
+	read_rsp.cmd_id = CLIENT_CMD_READ_LK_DEVICE_STATE;
+
+	/* Read the device info */
+	ret = qseecom_send_command(app_handle, (void*) &read_req, sizeof(read_req), (void*) &read_rsp, sizeof(read_rsp));
+
+	if (ret < 0 || read_rsp.status < 0)
+	{
+		dprintf(CRITICAL, "Reading device info failed: Error: %d\n", read_rsp.status);
+		return read_rsp.status;
+	}
+
+	return 0;
+}
+
+int write_device_info_rpmb(void *info, uint32_t sz)
+{
+	int ret = 0;
+
+	struct send_cmd_req write_req = {0};
+	struct send_cmd_rsp write_rsp = {0};
+
+	write_req.cmd_id = CLIENT_CMD_WRITE_LK_DEVICE_STATE;
+	write_req.data   = (uint32_t) info;
+	write_req.len    = sz;
+
+	write_rsp.cmd_id = CLIENT_CMD_WRITE_LK_DEVICE_STATE;
+
+	/* Write the device info */
+	ret = qseecom_send_command(app_handle, (void *)&write_req, sizeof(write_req), (void *)&write_rsp, sizeof(write_rsp));
+
+	if (ret < 0 || write_rsp.status < 0)
+	{
+		dprintf(CRITICAL, "Writing device info failed: Error: %d\n", write_rsp.status);
+		return ret;
+	}
+
+	return 0;
+}
+
+int rpmb_get_app_handle()
+{
+	return app_handle;
+}
+
+int rpmb_uninit()
+{
+	int ret = 0;
+
+	ret = rpmb_listener_stop(RPMB_LSTNR_ID);
+	if (ret < 0)
+	{
+		dprintf(CRITICAL, "Failed to stop Qseecom Listener\n");
+		return ret;
+	}
+	ret = qseecom_exit();
+
+	if (ret < 0)
+	{
+		dprintf(CRITICAL, "Failed to exit qseecom \n");
+		return ret;
+	}
+
+	return ret;
+}
+
+int load_sec_app()
+{
+	/* start TZ app */
+	app_handle = qseecom_start_app("lksecapp");
+
+	if (app_handle < 0)
+	{
+		dprintf(CRITICAL, "Failure to load TZ app: lksecapp, error: %d\n", app_handle);
+		return app_handle;
+	}
+
+	return 0;
+}
+
+int unload_sec_app()
+{
+	int ret = 0;
+
+	struct send_cmd_req req = {0};
+	struct send_cmd_rsp rsp = {0};
+
+	req.cmd_id = CLIENT_CMD_LK_END_MILESTONE;
+	rsp.cmd_id = CLIENT_CMD_LK_END_MILESTONE;
+
+	/* Milestone end command */
+	ret = qseecom_send_command(app_handle, (void *)&req, sizeof(req), (void *)&rsp, sizeof(rsp));
+
+	if (ret < 0 || rsp.status < 0)
+	{
+		dprintf(CRITICAL, "Failed to send milestone end command: Error: %x\n", rsp.status);
+		return ret;
+	}
+
+	if (qseecom_shutdown_app(app_handle) < 0)
+	{
+		dprintf(CRITICAL, "Failed to Shutdown sec app\n");
+		ASSERT(0);
+	}
+
+
+	return 0;
+}
+
+bool is_sec_app_loaded()
+{
+	return lksec_app_loaded;
+}
diff --git a/platform/msm_shared/rpmb/rpmb_emmc.c b/platform/msm_shared/rpmb/rpmb_emmc.c
new file mode 100644
index 0000000..2bfa545
--- /dev/null
+++ b/platform/msm_shared/rpmb/rpmb_emmc.c
@@ -0,0 +1,179 @@
+/* Copyright (c) 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
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rpmb.h>
+#include <mmc_sdhci.h>
+#include <debug.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,
+};
+
+int rpmb_write_emmc(struct mmc_device *dev,uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len)
+{
+	uint32_t i;
+	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++)
+	{
+#if DEBUG_RPMB
+		dump_rpmb_frame((uint8_t *)req_buf, "request");
+#endif
+
+		/* CMD25 program data packet */
+		cmd[0].write_flag = true;
+		cmd[0].cmd_index = CMD25_WRITE_MULTIPLE_BLOCK;
+		cmd[0].argument = 0;
+		cmd[0].cmd_type = SDHCI_CMD_TYPE_NORMAL;
+		cmd[0].resp_type = SDHCI_CMD_RESP_R1;
+		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;
+
+		/* CMD25 Result Register Read Request Packet */
+		cmd[1].write_flag = false;
+		cmd[1].cmd_index = CMD25_WRITE_MULTIPLE_BLOCK;
+		cmd[1].argument = 0;
+		cmd[1].cmd_type = SDHCI_CMD_TYPE_NORMAL;
+		cmd[1].resp_type = SDHCI_CMD_RESP_R1;
+		cmd[1].trans_mode = SDHCI_MMC_WRITE;
+		cmd[1].data_present = 0x1;
+		cmd[1].data.data_ptr = (void *)&read_result_reg;
+		cmd[1].data.num_blocks = RPMB_MIN_BLK_CNT;
+
+		/* Read actual result with read request */
+		cmd[2].write_flag = false;
+		cmd[2].cmd_index = CMD18_READ_MULTIPLE_BLOCK;
+		cmd[2].argument = 0;
+		cmd[2].cmd_type = SDHCI_CMD_TYPE_NORMAL;
+		cmd[2].resp_type = SDHCI_CMD_RESP_R1;
+		cmd[2].trans_mode = SDHCI_MMC_READ;
+		cmd[2].data_present = 0x1;
+		cmd[2].data.data_ptr = (void *)resp_buf;
+		cmd[2].data.num_blocks = RPMB_MIN_BLK_CNT;
+
+		ret = mmc_sdhci_rpmb_send(dev, cmd);
+
+		if (ret)
+		{
+			dprintf(CRITICAL, "Failed to Send the RPMB write sequnce of commands\n");
+			break;
+		}
+
+		if (result->result[0] == 0x80)
+		{
+			dprintf(CRITICAL, "Max write counter reached: \n");
+			break;
+		}
+
+		if (result->result[1])
+		{
+			dprintf(CRITICAL, "%s\n", str_err[result->result[1]]);
+			break;
+		}
+
+		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;
+
+	return 0;
+}
+
+int rpmb_read_emmc(struct mmc_device *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len)
+{
+	struct mmc_command cmd[3] = {{0}, {0}, {0}};
+	int ret = 0;
+	struct rpmb_frame *result = (struct rpmb_frame *)resp_buf;
+
+#if DEBUG_RPMB
+	dump_rpmb_frame((uint8_t *)req_buf, "request");
+#endif
+
+	/* CMD25 program data packet */
+	cmd[0].write_flag = false;
+	cmd[0].cmd_index = CMD25_WRITE_MULTIPLE_BLOCK;
+	cmd[0].argument = 0;
+	cmd[0].cmd_type = SDHCI_CMD_TYPE_NORMAL;
+	cmd[0].resp_type = SDHCI_CMD_RESP_R1;
+	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;
+
+	/* Read actual result with read request */
+	cmd[1].write_flag = false;
+	cmd[1].cmd_index = CMD18_READ_MULTIPLE_BLOCK;
+	cmd[1].argument = 0;
+	cmd[1].cmd_type = SDHCI_CMD_TYPE_NORMAL;
+	cmd[1].resp_type = SDHCI_CMD_RESP_R1;
+	cmd[1].trans_mode = SDHCI_MMC_READ;
+	cmd[1].data_present = 0x1;
+	cmd[1].data.data_ptr = (void *)resp_buf;
+	cmd[1].data.num_blocks = blk_cnt;
+	cmd[1].cmd23_support  = 0x1;
+
+	ret = mmc_sdhci_rpmb_send(dev, cmd);
+
+	if (ret)
+	{
+		dprintf(CRITICAL, "Failed to Send the RPMB read sequence of commands\n");
+		return -1;
+	}
+
+	if (result->result[1])
+	{
+		dprintf(CRITICAL, "%s\n", str_err[result->result[1]]);
+	}
+
+#if DEBUG_RPMB
+	dump_rpmb_frame((uint8_t *)resp_buf, "response");
+#endif
+	*resp_len = blk_cnt * RPMB_BLK_SIZE;
+
+	return 0;
+}
diff --git a/platform/msm_shared/rpmb/rpmb_listener.c b/platform/msm_shared/rpmb/rpmb_listener.c
new file mode 100644
index 0000000..7cf0b79
--- /dev/null
+++ b/platform/msm_shared/rpmb/rpmb_listener.c
@@ -0,0 +1,199 @@
+/* Copyright (c) 2013-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
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <debug.h>
+#include <rpmb.h>
+#include <rpmb_listener.h>
+#include <qseecom_lk_api.h>
+
+#define RPMB_LSTNR_VERSION_2        0x2
+
+typedef enum
+{
+	TZ_CM_CMD_RPMB_INIT = 0x101,    //257
+	TZ_CM_CMD_RPMB_READ,        //258
+	TZ_CM_CMD_RPMB_WRITE,       //259
+	TZ_CM_CMD_RPMB_PARTITION,   //260
+} tz_rpmb_cmd_type;
+
+struct tz_device_init_req
+{
+	uint32_t cmd_id;
+	uint32_t version;
+}__PACKED;
+
+/* RPMB Init response message */
+struct tz_device_init_resp
+{
+    uint32_t cmd_id;           /* Command ID */
+    uint32_t version;          /* Messaging version from RPMB listener */
+    uint32_t status;           /* RPMB init status */
+    uint32_t num_sectors;      /* Size of RPMB (in sectors) */
+    uint32_t rel_wr_count;     /* Reliable write count for the RPMB */
+    uint32_t dev_type;         /* Storage device type (like eMMC or UFS) */
+    uint32_t reserved1;        /* Reserved 1 */
+    uint32_t reserved2;        /* Reserved 2 */
+    uint32_t reserved3;        /* Reserved 3 */
+    uint32_t reserved4;        /* Reserved 4 */
+}__PACKED;
+
+struct tz_rpmb_rw_req
+{
+	uint32_t cmd_id;
+	uint32_t num_sectors;
+	uint32_t req_buff_len;
+	uint32_t req_buff_offset;
+}__PACKED;
+
+struct tz_rpmb_rw_resp
+{
+	uint32_t cmd_id;
+	int32_t  status;
+	uint32_t res_buff_len;
+	uint32_t res_buff_offset;
+}__PACKED;
+
+typedef int (*ListenerCallback)(void*, uint32_t);
+
+static void handle_init_request(void *buf, uint32_t sz)
+{
+	struct tz_device_init_req *init_req_p = NULL;
+	struct tz_device_init_resp *init_resp = (struct tz_device_init_resp*) buf;
+	struct rpmb_init_info *rpmb_info = NULL;
+
+	init_req_p = (struct tz_device_init_req *) buf;
+
+	rpmb_info = rpmb_get_init_info();
+
+	if (rpmb_info)
+		init_resp->status = 0;
+
+	init_resp->cmd_id = init_req_p->cmd_id;
+	init_resp->version = RPMB_LSTNR_VERSION_2;
+	init_resp->num_sectors = rpmb_info->size / RPMB_SECTOR_SIZE;
+	init_resp->rel_wr_count = rpmb_info->rel_wr_count;
+	init_resp->dev_type = rpmb_info->dev_type;
+}
+
+static void handle_rw_request(void *buf, uint32_t sz)
+{
+	struct tz_rpmb_rw_req *req_p = (struct tz_rpmb_rw_req *)buf;
+	struct tz_rpmb_rw_resp *resp_p = NULL;
+	uint32_t *req_buf = buf + req_p->req_buff_offset;
+	uint32_t *resp_buf = buf + sizeof(struct tz_rpmb_rw_resp);
+
+	resp_p = (struct tz_rpmb_rw_resp *) buf;
+
+	switch (req_p->cmd_id)
+	{
+		case TZ_CM_CMD_RPMB_READ:
+#if DEBUG_RPMB
+			dprintf(INFO, "Read Request received\n");
+#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");
+#endif
+			resp_p->status = rpmb_write(req_buf, req_p->num_sectors, resp_buf, &resp_p->res_buff_len);
+			break;
+		default:
+			dprintf(CRITICAL, "Unsupported request command request: %u\n", req_p->cmd_id);
+			ASSERT(0);
+	};
+
+	resp_p->res_buff_offset = sizeof(struct tz_rpmb_rw_resp);
+	resp_p->cmd_id = req_p->cmd_id;
+}
+
+int rpmb_cmd_handler(void *buf, uint32_t sz)
+{
+	int ret = 0;
+	uint32_t cmd_id;
+
+	ASSERT(buf);
+
+	cmd_id = (uint32_t) *((uint32_t *)buf);
+
+	switch(cmd_id)
+	{
+		case TZ_CM_CMD_RPMB_READ:
+		case TZ_CM_CMD_RPMB_WRITE:
+			handle_rw_request(buf, sz);
+			break;
+		case TZ_CM_CMD_RPMB_INIT:
+#if DEBUG_RPMB
+			dprintf(INFO, "RPMB init received\n");
+#endif
+			handle_init_request(buf, sz);
+			break;
+		case TZ_CM_CMD_RPMB_PARTITION:
+#if DEBUG_RPMB
+			dprintf(INFO, "Partition init received\n");
+#endif
+			ret = -1;
+			break;
+		default:
+			/* Does qseecom need a response here? */
+			dprintf(CRITICAL, "Unsupported Request from qseecom: %d\n", cmd_id);
+			ASSERT(0);
+	};
+
+	return ret;
+}
+
+int rpmb_listener_start()
+{
+	int ret;
+	struct qseecom_listener_services rpmb_listener;
+
+	rpmb_listener.service_name = "RPMB system services";
+	rpmb_listener.id           =  RPMB_LSTNR_ID;
+	rpmb_listener.sb_size      = 20 * 1024;
+	rpmb_listener.service_cmd_handler = rpmb_cmd_handler;
+
+	ret = qseecom_register_listener(&rpmb_listener);
+
+	if (ret < 0)
+		dprintf(CRITICAL, "Failed to register rpmb listener\n");
+
+	return ret;
+}
+
+int rpmb_listener_stop(int id)
+{
+	int ret;
+
+	ret = qseecom_deregister_listener(id);
+
+	if (ret < 0)
+		dprintf(CRITICAL, "Failed to unregister rpmb listener\n");
+
+	return ret;
+}
+
diff --git a/platform/msm_shared/rpmb/rpmb_ufs.c b/platform/msm_shared/rpmb/rpmb_ufs.c
new file mode 100644
index 0000000..3cc4d91
--- /dev/null
+++ b/platform/msm_shared/rpmb/rpmb_ufs.c
@@ -0,0 +1,294 @@
+/* Copyright (c) 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
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ufs.h>
+#include <ucs.h>
+#include <upiu.h>
+#include <rpmb.h>
+#include <debug.h>
+#include <stdlib.h>
+#include <string.h>
+#include <endian.h>
+#include <arch/defines.h>
+
+static struct rpmb_frame read_result_reg =
+{
+	.requestresponse[1] = READ_RESULT_FLAG,
+};
+
+int rpmb_read_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len)
+{
+	// validate input parameters
+	ASSERT(req_buf);
+	ASSERT(resp_buf);
+	ASSERT(resp_len);
+
+	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;
+	uint32_t                     blks_remaining;
+	uint32_t                     blks_to_transfer;
+	uint64_t                     bytes_to_transfer;
+	uint64_t                     max_size;
+	blks_remaining    = blk_cnt;
+	blks_to_transfer  = blks_remaining;
+	bytes_to_transfer = blks_to_transfer * RPMB_FRAME_SIZE;
+
+#ifdef DEBUG_RPMB
+	dump_rpmb_frame((uint8_t *)req_buf, "request");
+#endif
+
+	// check if total bytes to transfer exceed max supported size
+	max_size = dev->rpmb_rw_size * RPMB_FRAME_SIZE * blk_cnt;
+	if (bytes_to_transfer > max_size)
+	{
+		dprintf(CRITICAL, "RPMB request transfer size %llu greater than max transfer size %llu\n", bytes_to_transfer, max_size);
+		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",
+                   bytes_to_transfer, blks_to_transfer);
+#endif
+	// send the request
+	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(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 Read request\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 Read request complete\n");
+#endif
+	// read the response
+	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_IN;
+	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(bytes_to_transfer);
+
+	// 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) resp_buf;
+	req_upiu.data_len         = bytes_to_transfer;
+	req_upiu.flags            = UPIU_FLAGS_READ;
+	req_upiu.lun              = UFS_WLUN_RPMB;
+	req_upiu.dd               = UTRD_SYSTEM_TO_TARGET;
+
+#ifdef DEBUG_RPMB
+	dprintf(INFO, "Sending RPMB Read response\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(SPEW, "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)
+{
+	// validate input parameters
+	ASSERT(req_buf);
+	ASSERT(resp_buf);
+	ASSERT(resp_len);
+
+	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;
+	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;
+
+	blks_remaining    = blk_cnt;
+	blks_to_transfer  = blks_remaining;
+	bytes_to_transfer = blks_to_transfer * RPMB_FRAME_SIZE;
+
+	// check if total bytes to transfer exceed max supported size
+	max_size = dev->rpmb_rw_size * RPMB_FRAME_SIZE * blk_cnt;
+	if (bytes_to_transfer > max_size)
+	{
+		dprintf(CRITICAL, "RPMB request transfer size %llu greater than max transfer size %llu\n", bytes_to_transfer, max_size);
+		return -UFS_FAILURE;
+	}
+#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");
+#endif
+
+	for (i = 0; i < blk_cnt; i++)
+	{
+		// send the request
+		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
+		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         = 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;
+		req_upiu.lun              = UFS_WLUN_RPMB;
+		req_upiu.dd               = UTRD_TARGET_TO_SYSTEM;
+
+#ifdef DEBUG_RPMB
+		dprintf(INFO, "Sending RPMB Result Read Register: 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(SPEW, "Sending RPMB Result Read Register: Done\n");
+#endif
+
+		// Retrieve verification result
+		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_IN;
+		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) resp_buf;
+		req_upiu.data_len         = result_frame_bytes;
+		req_upiu.flags            = UPIU_FLAGS_READ;
+		req_upiu.lun              = UFS_WLUN_RPMB;
+		req_upiu.dd               = UTRD_SYSTEM_TO_TARGET;
+
+#ifdef DEBUG_RPMB
+		dprintf(INFO, "Sending RPMB Response for Result Read Register : 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(SPEW, "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);
+	}
+
+	*resp_len = RPMB_MIN_BLK_CNT * RPMB_BLK_SIZE;
+
+	return 0;
+}
diff --git a/platform/msm_shared/rpmb/rules.mk b/platform/msm_shared/rpmb/rules.mk
new file mode 100644
index 0000000..0e76433
--- /dev/null
+++ b/platform/msm_shared/rpmb/rules.mk
@@ -0,0 +1,8 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+INCLUDES += -I$(LOCAL_DIR)/include
+
+OBJS += $(LOCAL_DIR)/rpmb.o \
+		$(LOCAL_DIR)/rpmb_listener.o \
+		$(LOCAL_DIR)/rpmb_emmc.o \
+		$(LOCAL_DIR)/rpmb_ufs.o
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
old mode 100755
new mode 100644
index 793b88c..26eb012
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -533,3 +533,7 @@
 ifeq ($(ENABLE_PARTIAL_GOODS_SUPPORT), 1)
 	OBJS += $(LOCAL_DIR)/partial_goods.o
 endif
+
+ifeq ($(ENABLE_RPMB_SUPPORT), 1)
+include platform/msm_shared/rpmb/rules.mk
+endif