Merge "target: msm8909: Add check for h/w type before enabling UART"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 35373d8..0bae069 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -57,6 +57,9 @@
 #include <boot_device.h>
 #include <boot_verifier.h>
 #include <image_verify.h>
+#if USE_RPMB_FOR_DEVINFO
+#include <rpmb.h>
+#endif
 
 #if DEVICE_TREE
 #include <libfdt.h>
@@ -162,7 +165,7 @@
 /* Assuming unauthorized kernel image by default */
 static int auth_kernel_img = 0;
 
-static device_info device = {DEVICE_MAGIC, 0, 0, 0, 0, {0}};
+static device_info device = {DEVICE_MAGIC, 0, 0, 0, 0, {0}, {0},{0}};
 
 struct atag_ptbl_entry
 {
@@ -1445,7 +1448,6 @@
 BUF_DMA_ALIGN(info_buf, BOOT_IMG_MAX_PAGE_SIZE);
 void write_device_info_mmc(device_info *dev)
 {
-	struct device_info *info = (void*) info_buf;
 	unsigned long long ptn = 0;
 #if !VERIFIED_BOOT
 	unsigned long long size;
@@ -1473,14 +1475,12 @@
 	size = partition_get_size(index);
 #endif
 
-	memcpy(info, dev, sizeof(device_info));
-
 	blocksize = mmc_get_device_blocksize();
 
 #if VERIFIED_BOOT
-	if(mmc_write(ptn, blocksize, (void *)info_buf))
+	if(mmc_write(ptn, blocksize, (void *)dev))
 #else
-	if(mmc_write((ptn + size - blocksize), blocksize, (void *)info_buf))
+	if(mmc_write((ptn + size - blocksize), blocksize, (void *)dev))
 #endif
 	{
 		dprintf(CRITICAL, "ERROR: Cannot write device info\n");
@@ -1488,9 +1488,8 @@
 	}
 }
 
-void read_device_info_mmc(device_info *dev)
+void read_device_info_mmc(struct device_info *info)
 {
-	struct device_info *info = (void*) info_buf;
 	unsigned long long ptn = 0;
 #if !VERIFIED_BOOT
 	unsigned long long size;
@@ -1519,30 +1518,15 @@
 	blocksize = mmc_get_device_blocksize();
 
 #if VERIFIED_BOOT
-	if(mmc_read(ptn, (void *)info_buf, blocksize))
+	if(mmc_read(ptn, (void *)info, blocksize))
 #else
-	if(mmc_read((ptn + size - blocksize), (void *)info_buf, blocksize))
+	if(mmc_read((ptn + size - blocksize), (void *)info, blocksize))
 #endif
 	{
 		dprintf(CRITICAL, "ERROR: Cannot read device info\n");
 		return;
 	}
 
-	if (memcmp(info->magic, DEVICE_MAGIC, DEVICE_MAGIC_SIZE))
-	{
-		memcpy(info->magic, DEVICE_MAGIC, DEVICE_MAGIC_SIZE);
-#if DEFAULT_UNLOCK
-		info->is_unlocked = 1;
-#else
-		info->is_unlocked = 0;
-#endif
-		info->is_verified = 0;
-		info->is_tampered = 0;
-		info->charger_screen_enabled = 0;
-
-		write_device_info_mmc(info);
-	}
-	memcpy(dev, info, sizeof(device_info));
 }
 
 void write_device_info_flash(device_info *dev)
@@ -1614,7 +1598,15 @@
 {
 	if(target_is_emmc_boot())
 	{
-		write_device_info_mmc(dev);
+		struct device_info *info = (void*) info_buf;
+		memcpy(info, dev, sizeof(struct device_info));
+
+#if USE_RPMB_FOR_DEVINFO
+		if (is_secure_boot_enable())
+			write_device_info_rpmb((void*) info, mmc_get_device_blocksize());
+#else
+		write_device_info_mmc(info);
+#endif
 	}
 	else
 	{
@@ -1626,7 +1618,29 @@
 {
 	if(target_is_emmc_boot())
 	{
-		read_device_info_mmc(dev);
+		struct device_info *info = (void*) info_buf;
+
+#if USE_RPMB_FOR_DEVINFO
+		if (is_secure_boot_enable())
+			read_device_info_rpmb((void*) info, mmc_get_device_blocksize());
+#else
+		read_device_info_mmc(info);
+#endif
+
+		if (memcmp(info->magic, DEVICE_MAGIC, DEVICE_MAGIC_SIZE))
+		{
+			memcpy(info->magic, DEVICE_MAGIC, DEVICE_MAGIC_SIZE);
+			if (is_secure_boot_enable())
+				info->is_unlocked = 0;
+			else
+				info->is_unlocked = 1;
+			info->is_verified = 0;
+			info->is_tampered = 0;
+			info->charger_screen_enabled = 0;
+
+			write_device_info(info);
+		}
+		memcpy(dev, info, sizeof(device_info));
 	}
 	else
 	{
@@ -1724,7 +1738,7 @@
 #ifdef MDTP_SUPPORT
 	/* Go through Firmware Lock verification before continue with boot process */
 	mdtp_fwlock_verify_lock();
-	fbcon_clear();
+	display_image_on_screen();
 #endif /* MDTP_SUPPORT */
 
 #if VERIFIED_BOOT
@@ -2040,6 +2054,20 @@
 					img_header_entry[i].size);
 	}
 
+	if (!strncmp(arg, "bootloader", strlen("bootloader")))
+	{
+		strlcpy(device.bootloader_version, TARGET(BOARD), MAX_VERSION_LEN);
+		strlcat(device.bootloader_version, "-", MAX_VERSION_LEN);
+		strlcat(device.bootloader_version, meta_header->img_version, MAX_VERSION_LEN);
+	}
+	else
+	{
+		strlcpy(device.radio_version, TARGET(BOARD), MAX_VERSION_LEN);
+		strlcat(device.radio_version, "-", MAX_VERSION_LEN);
+		strlcat(device.radio_version, meta_header->img_version, MAX_VERSION_LEN);
+	}
+
+	write_device_info(&device);
 	fastboot_okay("");
 	return;
 }
@@ -2384,7 +2412,7 @@
 #ifdef MDTP_SUPPORT
 	/* Go through Firmware Lock verification before continue with boot process */
 	mdtp_fwlock_verify_lock();
-	fbcon_clear();
+	display_image_on_screen();
 #endif /* MDTP_SUPPORT */
 
 	if (target_is_emmc_boot())
@@ -2760,6 +2788,8 @@
 			device.display_panel);
 	fastboot_publish("display-panel",
 			(const char *) panel_display_mode);
+	fastboot_publish("version-bootloader", (const char *) device.bootloader_version);
+	fastboot_publish("version-baseband", (const char *) device.radio_version);
 }
 
 void aboot_init(const struct app_descriptor *app)
@@ -2868,7 +2898,7 @@
 #ifdef MDTP_SUPPORT
 			/* Go through Firmware Lock verification before continue with boot process */
 			mdtp_fwlock_verify_lock();
-			fbcon_clear();
+			display_image_on_screen();
 #endif /* MDTP_SUPPORT */
 
 			boot_linux_from_mmc();
diff --git a/app/aboot/devinfo.h b/app/aboot/devinfo.h
index bd78771..7eee69b 100644
--- a/app/aboot/devinfo.h
+++ b/app/aboot/devinfo.h
@@ -1,5 +1,5 @@
 /*
- * * Copyright (c) 2011,2014, The Linux Foundation. All rights reserved.
+ * * Copyright (c) 2011,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
@@ -35,6 +35,7 @@
 #define DEVICE_MAGIC "ANDROID-BOOT!"
 #define DEVICE_MAGIC_SIZE 13
 #define MAX_PANEL_ID_LEN 64
+#define MAX_VERSION_LEN  64
 
 struct device_info
 {
@@ -44,6 +45,8 @@
 	bool is_verified;
 	bool charger_screen_enabled;
 	char display_panel[MAX_PANEL_ID_LEN];
+	char bootloader_version[MAX_VERSION_LEN];
+	char radio_version[MAX_VERSION_LEN];
 };
 
 #endif
diff --git a/app/aboot/fastboot.c b/app/aboot/fastboot.c
index 4dc955d..6f1841f 100644
--- a/app/aboot/fastboot.c
+++ b/app/aboot/fastboot.c
@@ -2,7 +2,7 @@
  * Copyright (c) 2009, Google Inc.
  * All rights reserved.
  *
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * 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
@@ -428,10 +428,32 @@
 	fastboot_ack("OKAY", info);
 }
 
+static void getvar_all()
+{
+	struct fastboot_var *var;
+	char getvar_all[64];
+
+	for (var = varlist; var; var = var->next)
+	{
+		strlcpy((char *) getvar_all, var->name, sizeof(getvar_all));
+		strlcat((char *) getvar_all, ":", sizeof(getvar_all));
+		strlcat((char *) getvar_all, var->value, sizeof(getvar_all));
+		fastboot_info(getvar_all);
+		memset((void *) getvar_all, '\0', sizeof(getvar_all));
+	}
+	fastboot_okay("");
+}
+
 static void cmd_getvar(const char *arg, void *data, unsigned sz)
 {
 	struct fastboot_var *var;
 
+	if (!strncmp("all", arg, strlen(arg)))
+	{
+		getvar_all();
+		return;
+	}
+
 	for (var = varlist; var; var = var->next) {
 		if (!strcmp(var->name, arg)) {
 			fastboot_okay(var->value);
diff --git a/app/aboot/mdtp.c b/app/aboot/mdtp.c
index 60b97b0..9ae9890 100644
--- a/app/aboot/mdtp.c
+++ b/app/aboot/mdtp.c
@@ -76,7 +76,7 @@
 		return -1;
 	}
 
-	dprintf(INFO, "mdtp: read_DIP: SUCCESS, read %d bytes\n", actual_partition_size);
+	dprintf(SPEW, "mdtp: read_DIP: SUCCESS, read %d bytes\n", actual_partition_size);
 
 	return 0;
 }
@@ -85,7 +85,6 @@
 static int write_DIP(DIP_t *dip)
 {
 	unsigned long long ptn = 0;
-	uint32_t partition_size;
 	uint32_t block_size = mmc_get_device_blocksize();
 
 	int index = INVALID_PTN;
@@ -94,30 +93,25 @@
 
 	index = partition_get_index("dip");
 	ptn = partition_get_offset(index);
+
 	if(ptn == 0)
 	{
 		return -1;
 	}
 
-	partition_size = partition_get_size(index);
-
-	if(partition_size < size)
-	{
-		dprintf(CRITICAL, "mdtp: write_DIP: ERROR, DIP partition too small\n");
-		return -1;
-	}
-
-	if(mmc_write(ptn, ROUNDUP(size, block_size), (void *)dip))
+	if(mmc_write(ptn, ROUNDUP(sizeof(DIP_t), block_size), (void *)dip))
 	{
 		dprintf(CRITICAL, "mdtp: write_DIP: ERROR, cannot read DIP info\n");
 		return -1;
 	}
 
+	dprintf(SPEW, "mdtp: write_DIP: SUCCESS, write %d bytes\n", ROUNDUP(sizeof(DIP_t), block_size));
+
 	return 0;
 }
 
-/* Provision the DIP by storing the default DIP into the EMMC */
-static void provision_DIP()
+/* Deactivate MDTP by storing the default DIP into the EMMC */
+static void write_deactivated_DIP()
 {
 	DIP_t *enc_dip;
 	DIP_t *dec_dip;
@@ -126,14 +120,14 @@
 	enc_dip = malloc(sizeof(DIP_t));
 	if (enc_dip == NULL)
 	{
-		dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot allocate DIP\n");
+		dprintf(CRITICAL, "mdtp: write_deactivated_DIP: ERROR, cannot allocate DIP\n");
 		return;
 	}
 
 	dec_dip = malloc(sizeof(DIP_t));
 	if (dec_dip == NULL)
 	{
-		dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot allocate DIP\n");
+		dprintf(CRITICAL, "mdtp: write_deactivated_DIP: ERROR, cannot allocate DIP\n");
 		free(enc_dip);
 		return;
 	}
@@ -145,21 +139,14 @@
 	ret = mdtp_tzbsp_enc_hash_DIP(dec_dip, enc_dip);
 	if(ret < 0)
 	{
-		dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot cipher DIP\n");
+		dprintf(CRITICAL, "mdtp: write_deactivated_DIP: ERROR, cannot cipher DIP\n");
 		goto out;
 	}
 
 	ret = write_DIP(enc_dip);
 	if(ret < 0)
 	{
-		dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot write DIP\n");
-		goto out;
-	}
-
-	ret = mdtp_tzbsp_set_provisioned_fuse();
-	if(ret < 0)
-	{
-		dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot set DIP_PROVISIONED fuse\n\n");
+		dprintf(CRITICAL, "mdtp: write_deactivated_DIP: ERROR, cannot write DIP\n");
 		goto out;
 	}
 
@@ -178,7 +165,7 @@
 	uint32_t block_size = mmc_get_device_blocksize();
 	uint32_t actual_partition_size = ROUNDUP(size, block_size);
 
-	dprintf(INFO, "mdtp: verify_partition_single_hash: %s, %u\n", name, size);
+	dprintf(SPEW, "mdtp: verify_partition_single_hash: %s, %u\n", name, size);
 
 	ASSERT(name != NULL);
 	ASSERT(hash_table != NULL);
@@ -208,7 +195,7 @@
 		return -1;
 	}
 
-	dprintf(INFO, "verify_partition_single_hash: %s: VERIFIED!\n", name);
+	dprintf(SPEW, "verify_partition_single_hash: %s: VERIFIED!\n", name);
 
 	return 0;
 }
@@ -228,7 +215,7 @@
 	uint32_t bytes_to_read;
 	uint32_t block_num = 0;
 
-	dprintf(INFO, "mdtp: verify_partition_block_hash: %s, %u\n", name, size);
+	dprintf(SPEW, "mdtp: verify_partition_block_hash: %s, %u\n", name, size);
 
 	ASSERT(name != NULL);
 	ASSERT(hash_table != NULL);
@@ -287,7 +274,7 @@
 		force_verify_block += 1;
 	}
 
-	dprintf(INFO, "verify_partition_block_hash: %s: VERIFIED!\n", name);
+	dprintf(SPEW, "verify_partition_block_hash: %s: VERIFIED!\n", name);
 
 	return 0;
 }
@@ -321,6 +308,75 @@
 	return 0;
 }
 
+/* Display the recovery UI to allow the user to enter the PIN and continue boot */
+static int display_recovery_ui(DIP_t *dip)
+{
+	uint32_t pin_length = 0;
+	char entered_pin[MDTP_MAX_PIN_LEN+1] = {0};
+	uint32_t i;
+	uint32_t equal_count = 0, different_count = 0;
+
+	if (dip->mdtp_cfg.enable_local_pin_authentication)
+	{
+		dprintf(SPEW, "mdtp: display_recovery_ui: Local deactivation enabled\n");
+
+		pin_length = strlen(dip->mdtp_cfg.mdtp_pin.mdtp_pin);
+
+		if (pin_length > MDTP_MAX_PIN_LEN || pin_length < MDTP_MIN_PIN_LEN)
+		{
+			dprintf(CRITICAL, "mdtp: display_recovery_ui: Error, invalid PIN length\n");
+			display_error_msg();
+			return -1;
+		}
+
+		// Set entered_pin to initial '0' string + null terminator
+		for (i=0; i<pin_length; i++)
+		{
+			entered_pin[i] = '0';
+		}
+
+		// Allow the user to enter the PIN as many times as he wishes
+		// (with INVALID_PIN_DELAY_MSECONDS after each failed attempt)
+		while (1)
+		{
+		    get_pin_from_user(entered_pin, pin_length);
+
+		    // Go over the entire PIN in any case, to prevent side-channel attacks
+		    for (i=0; i<pin_length; i++)
+		    {
+		        if (dip->mdtp_cfg.mdtp_pin.mdtp_pin[i] == entered_pin[i])
+		            equal_count++;
+		        else
+		            different_count++;
+		    }
+
+		    if (equal_count == pin_length)
+		    {
+		        // Valid PIN - deactivate and continue boot
+		        dprintf(SPEW, "mdtp: display_recovery_ui: valid PIN, continue boot\n");
+		        write_deactivated_DIP();
+		        return 0;
+		    }
+		    else
+		    {
+		        // Invalid PIN - display an appropriate message (which also includes a wait
+		        // for INVALID_PIN_DELAY_MSECONDS), and allow the user to try again
+		        dprintf(CRITICAL, "mdtp: display_recovery_ui: ERROR, invalid PIN\n");
+		        display_invalid_pin_msg();
+
+		        equal_count = 0;
+		        different_count = 0;
+		    }
+		}
+	}
+	else
+	{
+		dprintf(CRITICAL, "mdtp: display_recovery_ui: Local deactivation disabled, unable to display recovery UI\n");
+		display_error_msg();
+		return -1;
+	}
+}
+
 /* Verify all protected partitinons according to the DIP */
 static int verify_all_partitions(DIP_t *dip, verify_result_t *verify_result)
 {
@@ -340,8 +396,6 @@
 	}
 	else if (dip->status == DIP_STATUS_ACTIVATED)
 	{
-		show_checking_msg();
-
 		for(i=0; i<MAX_PARTITIONS; i++)
 		{
 			if(dip->partition_cfg[i].lock_enabled && dip->partition_cfg[i].size)
@@ -361,14 +415,12 @@
 		if (verify_failure)
 		{
 			dprintf(CRITICAL, "mdtp: verify_all_partitions: Failed partition verification\n");
-			show_invalid_msg();
-			return -1;
+			return 0;
 		}
 
 	}
 
 	*verify_result = VERIFY_OK;
-	show_OK_msg();
 	return 0;
 }
 
@@ -385,14 +437,14 @@
 	enc_dip = malloc(ROUNDUP(sizeof(DIP_t), block_size));
 	if (enc_dip == NULL)
 	{
-		dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot allocate DIP\n");
+		dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, cannot allocate DIP\n");
 		return;
 	}
 
 	dec_dip = malloc(ROUNDUP(sizeof(DIP_t), block_size));
 	if (dec_dip == NULL)
 	{
-		dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot allocate DIP\n");
+		dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, cannot allocate DIP\n");
 		free(enc_dip);
 		return;
 	}
@@ -410,7 +462,7 @@
 	if(ret < 0)
 	{
 		dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, cannot verify DIP\n");
-		show_invalid_msg();
+		display_error_msg();
 		goto out;
 	}
 
@@ -418,7 +470,7 @@
 	if(!verified)
 	{
 		dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, corrupted DIP\n");
-		show_invalid_msg();
+		display_error_msg();
 		goto out;
 	}
 
@@ -432,14 +484,15 @@
 
 	if (verify_result == VERIFY_OK)
 	{
-		dprintf(INFO, "mdtp: validate_DIP_and_firmware: Verify OK\n");
+		dprintf(SPEW, "mdtp: validate_DIP_and_firmware: Verify OK\n");
 	}
 	else if (verify_result  == VERIFY_FAILED)
 	{
 		dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, corrupted firmware\n");
+		display_recovery_ui(dec_dip);
 	} else /* VERIFY_SKIPPED */
 	{
-		dprintf(INFO, "mdtp: validate_DIP_and_firmware: Verify skipped\n");
+		dprintf(SPEW, "mdtp: validate_DIP_and_firmware: Verify skipped\n");
 	}
 
 out:
diff --git a/app/aboot/mdtp.h b/app/aboot/mdtp.h
index 9975899..d40807a 100644
--- a/app/aboot/mdtp.h
+++ b/app/aboot/mdtp.h
@@ -34,9 +34,13 @@
 #define MAX_PARTITIONS 3
 #define MAX_PARTITION_NAME_LEN 100
 #define HASH_LEN 32
+#define MDTP_MIN_PIN_LEN 5
 #define MDTP_MAX_PIN_LEN 8
 #define DIP_PADDING 11
 
+#define INITIAL_DELAY_MSECONDS      5000
+#define INVALID_PIN_DELAY_MSECONDS  5000
+
 #define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
 #define MDTP_FWLOCK_BLOCK_SIZE (1024*1024*16)
 #define MDTP_FWLOCK_MAX_FILES (100)
@@ -104,19 +108,59 @@
 	VERIFY_FAILED,
 } verify_result_t;
 
-/* Start Firmware Lock verification process */
+
+/**
+ * mdtp_fwlock_verify_lock
+ *
+ * Start Firmware Lock verification process.
+ *
+ * @return - negative value for an error, 0 for success.
+ */
 int mdtp_fwlock_verify_lock();
 
-/* Return whether the MDTP is currently enabled or disabled in HW */
+/**
+ * mdtp_fuse_get_enabled
+ *
+ * Return whether the MDTP is currently enabled or
+ * disabled in HW.
+ *
+ * @param[out] enabled: set to true if MDTP enabled,
+ * false otherwise.
+ *
+ * @return - negative value for an error, 0 for success.
+ */
 int mdtp_fuse_get_enabled(bool *enabled);
 
-/* Display the "Firmware Valid" screen */
-void show_OK_msg();
+/**
+ * get_pin_from_user
+ *
+ * Display the recovery PIN screen and set received buffer
+ * with the PIN the user has entered.
+ *
+ * @param[out] entered_pin: buffer holding the received PIN.
+ * @param[in]  pin_length:  PIN length (and also entered_pin buffer length).
+ *
+ * @return - None.
+ */
+void get_pin_from_user(char *entered_pin, uint32_t pin_length);
 
-/* Display the "Firmware Invalid" screen */
-void show_invalid_msg();
+/**
+ * display_invalid_pin_msg
+ *
+ * User has entered invalid PIN, display error message and
+ * allow the user to try again.
+ *
+ * @return - None.
+ */
+void display_invalid_pin_msg();
 
-/* Display the "Verifying Firmware" screen */
-void show_checking_msg();
+/**
+ * display_error_msg
+ *
+ * Display error message and stop boot process.
+ *
+ * @return - None.
+ */
+void display_error_msg();
 
 #endif
diff --git a/app/aboot/mdtp_ui.c b/app/aboot/mdtp_ui.c
index 30d70d6..48d899e 100644
--- a/app/aboot/mdtp_ui.c
+++ b/app/aboot/mdtp_ui.c
@@ -32,31 +32,88 @@
 #include <mmc.h>
 #include <partition_parser.h>
 #include <stdlib.h>
+#include <string.h>
 #include "mdtp.h"
 
-#define MDTP_IMAGE_WIDTH 500
-#define MDTP_IMAGE_HEIGHT 800
-#define MDTP_UX_DELAY 1000
-#define MDTP_OK_OFFSET 0x0
-#define MDTP_CHECKING_OFFSET 0x200000
-#define MDTP_INVALID_OFFSET 0x400000
-#define MDTP_RECOVERED_OFFSET 0x600000
+// Image dimensions
+#define MDTP_ERROR_MSG_WIDTH                (1412)
+#define MDTP_ERROR_MSG_HEIGHT               (212)
+#define MDTP_MAIN_TEXT_WIDTH                (1364)
+#define MDTP_MAIN_TEXT_HEIGHT               (288)
+#define MDTP_PIN_DIGIT_WIDTH                (180)
+#define MDTP_PIN_DIGIT_HEIGHT               (180)
+#define MDTP_OK_BUTTON_WIDTH                (644)
+#define MDTP_OK_BUTTON_HEIGHT               (158)
+#define MDTP_DIGITS_INSTRUCTIONS_WIDTH      (1384)
+#define MDTP_DIGITS_INSTRUCTIONS_HEIGHT     (166)
+#define MDTP_PIN_INSTRUCTIONS_WIDTH         (920)
+#define MDTP_PIN_INSTRUCTIONS_HEIGHT        (204)
 
-extern uint32_t target_volume_down(void);
-extern void fbcon_putImage(struct fbimage *fbimg, bool flag);
+// Image offsets
+#define MDTP_ERROR_MSG_OFFSET               (0x1000)
+#define MDTP_INITIAL_DELAY_OFFSET           (0xDD000)
+#define MDTP_ENTER_PIN_OFFSET               (0x1FD000)
+#define MDTP_INVALID_PIN_OFFSET             (0x31D000)
+#define MDTP_PIN_DIGIT_0_OFFSET             (0x43D000)
+#define MDTP_PIN_DIGITS_OFFSET              (0x18000)
+#define MDTP_PIN_SELECTED_DIGIT_0_OFFSET    (MDTP_PIN_DIGIT_0_OFFSET + 10*MDTP_PIN_DIGITS_OFFSET)  // (0x52D000)
+#define MDTP_OK_BUTTON_OFFSET               (0x61D000)
+#define MDTP_SELECTED_OK_BUTTON_OFFSET      (0x668000)
+#define MDTP_DIGITS_INSTRUCTIONS_OFFSET     (0x6B3000)
+#define MDTP_PIN_INSTRUCTIONS_OFFSET        (0x75C000)
+
+// Image releative locations
+#define ERROR_MESSAGE_RELATIVE_Y_LOCATION   (0.18)
+#define MAIN_TEXT_RELATIVE_Y_LOCATION       (0.33)
+#define PIN_RELATIVE_Y_LOCATION             (0.47)
+#define PIN_TEXT_RELATIVE_Y_LOCATION        (0.57)
+#define OK_BUTTON_RELATIVE_Y_LOCATION       (0.75)
+#define OK_TEXT_RELATIVE_Y_LOCATION         (0.82)
+
+#define DIGIT_SPACE                         (12)
+
+#define MDTP_PRESSING_DELAY_MSEC            (400)
+#define MDTP_MAX_IMAGE_SIZE                 (1183000)  //size in bytes, includes some extra bytes since we round up to block size in read
+#define RGB888_BLACK                        (0x000000)
+#define BITS_PER_BYTE                       (8)
+
+
+#define CENTER_IMAGE_ON_X_AXIS(image_width,screen_width)         ((screen_width-image_width)/2)
+
 extern void mdelay(unsigned msecs);
+extern uint32_t target_volume_up();
+extern uint32_t target_volume_down();
 
-static struct fbimage mdtp_header;/* = {0};*/
+struct mdtp_fbimage {
+    uint32_t width;
+    uint32_t height;
+    uint8_t image[MDTP_MAX_IMAGE_SIZE];
+};
 
-/********************************************************************************/
+/*----------------------------------------------------------------------------
+ * Global Variables
+ * -------------------------------------------------------------------------*/
 
-/* Load the "Firmware Valid" image from EMMC */
-static struct fbimage* mdtp_images_mmc_OK()
+static uint32_t g_pin_frames_x_location[MDTP_MAX_PIN_LEN] = {0};
+static uint32_t g_pin_frames_y_location = 0;
+
+static bool g_initial_screen_displayed = false;
+
+static struct mdtp_fbimage g_mdtp_header;
+static struct fbcon_config *fb_config = NULL;
+
+/*----------------------------------------------------------------------------
+ * Local Functions
+ * -------------------------------------------------------------------------*/
+
+/**
+ * Load images from EMMC
+ */
+static struct mdtp_fbimage* mdtp_read_mmc_image(uint32_t offset, uint32_t width, uint32_t height)
 {
 	int index = INVALID_PTN;
 	unsigned long long ptn = 0;
-	struct fbcon_config *fb_display = NULL;
-	struct fbimage *logo = &mdtp_header;
+	struct mdtp_fbimage *logo = &g_mdtp_header;
 	uint32_t block_size = mmc_get_device_blocksize();
 
 	index = partition_get_index("mdtp");
@@ -71,231 +128,475 @@
 		return NULL;
 	}
 
-	fb_display = fbcon_display();
-	if (fb_display)
+	if (fb_config)
 	{
-		uint8_t *base = (uint8_t *) fb_display->base;
-		base += LOGO_IMG_OFFSET;
+		uint8_t *base = logo->image;
 
-		if (mmc_read(ptn, (void*)base, ROUNDUP(MDTP_IMAGE_WIDTH*MDTP_IMAGE_HEIGHT*3, block_size))) {
+		if (mmc_read(ptn+offset, (void*)base, ROUNDUP(width*height*3, block_size))) {
 				fbcon_clear();
 				dprintf(CRITICAL, "ERROR: mdtp image read failed\n");
 				return NULL;
 		}
-		logo->image = base;
+		logo->width = width;
+		logo->height = height;
 	}
 
 	return logo;
 }
 
-/* Load the "Firmware Invalid" image from EMMC */
-static struct fbimage* mdtp_images_mmc_INVALID()
+/**
+ * flush fbcon display
+ *
+ * The function is duplicated from fbcon.c
+ */
+static void fbcon_flush(void)
 {
-	int index = INVALID_PTN;
-	unsigned long long ptn = 0;
-	struct fbcon_config *fb_display = NULL;
-	struct fbimage *logo = &mdtp_header;
-	uint32_t block_size = mmc_get_device_blocksize();
+	if (fb_config->update_start)
+		fb_config->update_start();
+	if (fb_config->update_done)
+		while (!fb_config->update_done());
+}
 
-	index = partition_get_index("mdtp");
-	if (index == 0) {
-		dprintf(CRITICAL, "ERROR: mdtp Partition table not found\n");
-		return NULL;
-	}
+/**
+ * Clear complete section on the screen.
+ * The section is of section_height, and is located from the y
+ * coordinate and down.
+ */
+static void fbcon_clear_section(uint32_t y, uint32_t section_height)
+{
+	unsigned image_base;
+	unsigned bytes_per_bpp;
 
-	ptn = partition_get_offset(index);
-	if (ptn == 0) {
-		dprintf(CRITICAL, "ERROR: mdtp Partition invalid\n");
-		return NULL;
-	}
-
-	fb_display = fbcon_display();
-	if (fb_display)
+	if (fb_config)
 	{
-		uint8_t *base = (uint8_t *) fb_display->base;
-		base += LOGO_IMG_OFFSET;
+	    image_base = (y *(fb_config->width));
+		bytes_per_bpp = ((fb_config->bpp) / BITS_PER_BYTE);
 
-		if (mmc_read(ptn+MDTP_INVALID_OFFSET, (void*)base, ROUNDUP(MDTP_IMAGE_WIDTH*MDTP_IMAGE_HEIGHT*3, block_size))) {
-				fbcon_clear();
-				dprintf(CRITICAL, "ERROR: mdtp image read failed\n");
-				return NULL;
-		}
-		logo->image = base;
+		unsigned count = fb_config->width*section_height;
+		memset(fb_config->base + image_base*bytes_per_bpp, RGB888_BLACK, count*bytes_per_bpp);
+
+		fbcon_flush();
 	}
-
-	return logo;
-}
-
-/* Load the "Verifying Firmware" image from EMMC */
-static struct fbimage* mdtp_images_mmc_CHECKING()
-{
-	int index = INVALID_PTN;
-	unsigned long long ptn = 0;
-	struct fbcon_config *fb_display = NULL;
-	struct fbimage *logo = &mdtp_header;
-	uint32_t block_size = mmc_get_device_blocksize();
-
-	index = partition_get_index("mdtp");
-	if (index == 0) {
-		dprintf(CRITICAL, "ERROR: mdtp Partition table not found\n");
-		return NULL;
-	}
-
-	ptn = partition_get_offset(index);
-	if (ptn == 0) {
-		dprintf(CRITICAL, "ERROR: mdtp Partition invalid\n");
-		return NULL;
-	}
-
-	fb_display = fbcon_display();
-	if (fb_display)
+	else
 	{
-		uint8_t *base = (uint8_t *) fb_display->base;
-		base += LOGO_IMG_OFFSET;
-
-		if (mmc_read(ptn+MDTP_CHECKING_OFFSET, (void*)base, ROUNDUP(MDTP_IMAGE_WIDTH*MDTP_IMAGE_HEIGHT*3, block_size))) {
-				fbcon_clear();
-				dprintf(CRITICAL, "ERROR: mdtp image read failed\n");
-				return NULL;
-		}
-		logo->image = base;
+	    dprintf(CRITICAL,"ERROR: fbcon_config struct is NULL\n");
+	    display_error_msg();
 	}
-
-	return logo;
 }
 
-/* Load the "Verifying Firmware" image from EMMC */
-static struct fbimage* mdtp_images_mmc_RECOVERED()
+/**
+ * Put image at a specific (x,y) location on the screen.
+ * Duplicated from fbcon.c, with modifications to allow (x,y) location (instead of a centered image),
+ * and display bmp images properly (order of copying the lines to the screen was reversed)
+ */
+static void fbcon_putImage_in_location(struct mdtp_fbimage *fbimg, uint32_t x, uint32_t y)
 {
-	int index = INVALID_PTN;
-	unsigned long long ptn = 0;
-	struct fbcon_config *fb_display = NULL;
-	struct fbimage *logo = &mdtp_header;
-	uint32_t block_size = mmc_get_device_blocksize();
+    unsigned i = 0;
+    unsigned bytes_per_bpp;
+    unsigned image_base;
+    unsigned width, pitch, height;
+    unsigned char *logo_base = NULL;
 
-	index = partition_get_index("mdtp");
-	if (index == 0) {
-		dprintf(CRITICAL, "ERROR: mdtp Partition table not found\n");
-		return NULL;
+    if (!fb_config) {
+		dprintf(CRITICAL,"ERROR: NULL configuration, image cannot be displayed\n");
+		return;
 	}
 
-	ptn = partition_get_offset(index);
-	if (ptn == 0) {
-		dprintf(CRITICAL, "ERROR: mdtp Partition invalid\n");
-		return NULL;
+	if(fbimg) {
+		width = pitch = fbimg->width;
+		height = fbimg->height;
+		logo_base = (unsigned char *)fbimg->image;
+	}
+	else {
+	    dprintf(CRITICAL,"ERROR: invalid image struct\n");
+	    return;
 	}
 
-	fb_display = fbcon_display();
-	if (fb_display)
+	bytes_per_bpp = ((fb_config->bpp) / BITS_PER_BYTE);
+
+#if DISPLAY_TYPE_MIPI
+	if (bytes_per_bpp == 3)
 	{
-		uint8_t *base = (uint8_t *) fb_display->base;
-		base += LOGO_IMG_OFFSET;
+		if (fbimg->width == fb_config->width && fbimg->height == fb_config->height)
+			return;
 
-		if (mmc_read(ptn+MDTP_RECOVERED_OFFSET, (void*)base, ROUNDUP(MDTP_IMAGE_WIDTH*MDTP_IMAGE_HEIGHT*3, block_size))) {
-				fbcon_clear();
-				dprintf(CRITICAL, "ERROR: mdtp image read failed\n");
-				return NULL;
+		if (fbimg->width > fb_config->width || fbimg->height > fb_config->height)
+		{
+		    dprintf(CRITICAL,"ERROR: invalid image size, larger than the screen\n");
+		    return;
 		}
-		logo->image = base;
+
+		image_base = ( (y *(fb_config->width)) + x);
+		for (i = 0; i < height; i++) {
+			memcpy (fb_config->base + ((image_base + (i * (fb_config->width))) * bytes_per_bpp),
+				logo_base + ((height - 1 - i) * pitch * bytes_per_bpp), width * bytes_per_bpp);
+		}
 	}
 
-	return logo;
+	fbcon_flush();
+
+#if DISPLAY_MIPI_PANEL_NOVATEK_BLUE
+	if(is_cmd_mode_enabled())
+        mipi_dsi_cmd_mode_trigger();
+#endif
+
+#else
+    if (bytes_per_bpp == 2)
+    {
+        for (i = 0; i < fbimg->width; i++)
+        {
+            memcpy (fb_config->base + ((image_base + (i * (fb_config->width))) * bytes_per_bpp),
+		   fbimg->image + (i * fbimg->height * bytes_per_bpp),
+		   fbimg->height * bytes_per_bpp);
+        }
+    }
+    fbcon_flush();
+#endif
 }
 
-/* Show the "Firmware Valid" image */
-static void display_image_on_screen_OK()
+/**
+ * Display main error message
+ */
+static int display_error_message()
 {
-	struct fbimage *fbimg;
+    struct mdtp_fbimage *fbimg;
 
-	fbcon_clear();
-	fbimg = mdtp_images_mmc_OK();
-	fbimg->header.width = MDTP_IMAGE_WIDTH;
-	fbimg->header.height = MDTP_IMAGE_HEIGHT;
+    fb_config = fbcon_display();
 
-	dprintf(CRITICAL, "display_image_on_screen_OK\n");
-	fbcon_putImage(fbimg, true);
+    if (fb_config)
+	{
+        uint32_t x = CENTER_IMAGE_ON_X_AXIS(MDTP_ERROR_MSG_WIDTH,fb_config->width);
+		uint32_t y = ((fb_config->height)*ERROR_MESSAGE_RELATIVE_Y_LOCATION);
+
+        fbimg = mdtp_read_mmc_image(MDTP_ERROR_MSG_OFFSET, MDTP_ERROR_MSG_WIDTH, MDTP_ERROR_MSG_HEIGHT);
+        if (NULL == fbimg)
+        {
+            dprintf(CRITICAL,"ERROR: failed to read error image from mmc\n");
+            return -1;
+        }
+
+        fbcon_putImage_in_location(fbimg, x, y);
+
+		return 0;
+	}
+	else
+	{
+	    dprintf(CRITICAL,"ERROR: fbcon_config struct is NULL\n");
+		return -1;
+	}
 }
 
-/* Show the "Firmware Invalid" image */
-static void display_image_on_screen_INVALID()
+/**
+ * Read from mmc the image in the given offset, of the given width and height.
+ * Then, display the image on the screen in the given (x,y) location.
+ */
+static void display_image(uint32_t offset, uint32_t width, uint32_t height, uint32_t x, uint32_t y)
 {
-	struct fbimage *fbimg;
+    struct mdtp_fbimage *fbimg;
 
-	fbcon_clear();
-	fbimg = mdtp_images_mmc_INVALID();
-	fbimg->header.width = MDTP_IMAGE_WIDTH;
-	fbimg->header.height = MDTP_IMAGE_HEIGHT;
+    if (fb_config)
+    {
+        fbimg = mdtp_read_mmc_image(offset, width, height);
+        if (NULL == fbimg)
+        {
+            dprintf(CRITICAL,"ERROR: failed to read image from mmc\n");
+            display_error_msg();
+        }
 
-	dprintf(CRITICAL, "display_image_on_screen_INVALID\n");
-	fbcon_putImage(fbimg, true);
+        fbcon_putImage_in_location(fbimg, x, y);
+    }
+    else
+    {
+        dprintf(CRITICAL,"ERROR: fbcon_config struct is NULL\n");
+        display_error_msg();
+    }
 }
 
-/* Show the "Verifying Firmware" image */
-static void display_image_on_screen_CHECKING()
+/**
+ * Display initial delay message
+ */
+static void display_initial_delay()
 {
-	struct fbimage *fbimg;
+    uint32_t x = CENTER_IMAGE_ON_X_AXIS(MDTP_MAIN_TEXT_WIDTH,fb_config->width);
+	uint32_t y = (fb_config->height)*MAIN_TEXT_RELATIVE_Y_LOCATION;
 
-	fbcon_clear();
-	fbimg = mdtp_images_mmc_CHECKING();
-	fbimg->header.width = MDTP_IMAGE_WIDTH;
-	fbimg->header.height = MDTP_IMAGE_HEIGHT;
-
-	dprintf(CRITICAL, "display_image_on_screen_CHECKING\n");
-	fbcon_putImage(fbimg, true);
+	display_image(MDTP_INITIAL_DELAY_OFFSET, MDTP_MAIN_TEXT_WIDTH, MDTP_MAIN_TEXT_HEIGHT, x, y);
 }
 
-/* Show the "Verifying Firmware" image */
-static void display_image_on_screen_RECOVERED()
+/**
+ * Display "enter PIN" message
+ */
+static void display_enter_pin()
 {
-	struct fbimage *fbimg;
+    uint32_t x = CENTER_IMAGE_ON_X_AXIS(MDTP_MAIN_TEXT_WIDTH,fb_config->width);
+	uint32_t y = (fb_config->height)*MAIN_TEXT_RELATIVE_Y_LOCATION;
 
-	fbcon_clear();
-	fbimg = mdtp_images_mmc_RECOVERED();
-	fbimg->header.width = MDTP_IMAGE_WIDTH;
-	fbimg->header.height = MDTP_IMAGE_HEIGHT;
-
-	dprintf(CRITICAL, "display_image_on_screen_RECOVERED\n");
-	fbcon_putImage(fbimg, true);
+	display_image(MDTP_ENTER_PIN_OFFSET, MDTP_MAIN_TEXT_WIDTH, MDTP_MAIN_TEXT_HEIGHT, x, y);
 }
 
-/* Display the "Firmware Valid" screen */
-void show_OK_msg()
+/**
+ * Display invalid PIN message
+ */
+static void display_invalid_pin()
 {
-	display_image_on_screen_OK();
-	mdelay(MDTP_UX_DELAY);
+    uint32_t x = CENTER_IMAGE_ON_X_AXIS(MDTP_MAIN_TEXT_WIDTH,fb_config->width);
+	uint32_t y = (fb_config->height)*MAIN_TEXT_RELATIVE_Y_LOCATION;
 
-	return;
+	display_image(MDTP_INVALID_PIN_OFFSET, MDTP_MAIN_TEXT_WIDTH, MDTP_MAIN_TEXT_HEIGHT, x, y);
 }
 
-/* Display the "Firmware Invalid" screen */
-void show_invalid_msg()
+/**
+ * Clear digits instructions
+ */
+static void display_digits_instructions()
 {
-	display_image_on_screen_INVALID();
+    uint32_t x = CENTER_IMAGE_ON_X_AXIS(MDTP_DIGITS_INSTRUCTIONS_WIDTH,fb_config->width);
+	uint32_t y = (fb_config->height)*PIN_TEXT_RELATIVE_Y_LOCATION;
+
+	display_image(MDTP_DIGITS_INSTRUCTIONS_OFFSET, MDTP_DIGITS_INSTRUCTIONS_WIDTH, MDTP_DIGITS_INSTRUCTIONS_HEIGHT, x, y);
+}
+
+/**
+ * Clear digits instructions
+ */
+static void clear_digits_instructions()
+{
+    uint32_t y = (fb_config->height)*PIN_TEXT_RELATIVE_Y_LOCATION;
+
+    fbcon_clear_section(y, MDTP_DIGITS_INSTRUCTIONS_HEIGHT);
+}
+
+/**
+ * Display a digit as un-selected.
+ */
+static void display_digit(uint32_t x, uint32_t y, uint32_t digit)
+{
+    display_image(MDTP_PIN_DIGIT_0_OFFSET + digit*MDTP_PIN_DIGITS_OFFSET,
+            MDTP_PIN_DIGIT_WIDTH, MDTP_PIN_DIGIT_HEIGHT, x, y);
+}
+
+/**
+ * Display a digit as selected.
+ */
+static void display_selected_digit(uint32_t x, uint32_t y, uint32_t digit)
+{
+    display_image(MDTP_PIN_SELECTED_DIGIT_0_OFFSET + digit*MDTP_PIN_DIGITS_OFFSET,
+			MDTP_PIN_DIGIT_WIDTH, MDTP_PIN_DIGIT_HEIGHT, x, y);
+}
+
+/**
+ * Display OK button as un-selected.
+ */
+static void display_ok_button()
+{
+    uint32_t ok_x = CENTER_IMAGE_ON_X_AXIS(MDTP_OK_BUTTON_WIDTH,fb_config->width);
+	uint32_t ok_y = (fb_config->height)*OK_BUTTON_RELATIVE_Y_LOCATION;
+
+	display_image(MDTP_OK_BUTTON_OFFSET, MDTP_OK_BUTTON_WIDTH, MDTP_OK_BUTTON_HEIGHT, ok_x, ok_y);
+}
+
+/**
+ * Display OK button as selected.
+ */
+static void display_selected_ok_button()
+{
+    uint32_t ok_x = CENTER_IMAGE_ON_X_AXIS(MDTP_OK_BUTTON_WIDTH,fb_config->width);
+	uint32_t ok_y = (fb_config->height)*OK_BUTTON_RELATIVE_Y_LOCATION;
+
+	display_image(MDTP_SELECTED_OK_BUTTON_OFFSET, MDTP_OK_BUTTON_WIDTH, MDTP_OK_BUTTON_HEIGHT,  ok_x, ok_y);
+}
+
+/**
+ * Display the instructions for the OK button.
+ */
+static void display_pin_instructions()
+{
+    uint32_t x = CENTER_IMAGE_ON_X_AXIS(MDTP_PIN_INSTRUCTIONS_WIDTH,fb_config->width);
+	uint32_t y = (fb_config->height)*OK_TEXT_RELATIVE_Y_LOCATION;
+
+	display_image(MDTP_PIN_INSTRUCTIONS_OFFSET, MDTP_PIN_INSTRUCTIONS_WIDTH, MDTP_PIN_INSTRUCTIONS_HEIGHT, x, y);
+}
+
+/**
+ * Clear the instructions for the OK button.
+ */
+static void clear_pin_message()
+{
+    uint32_t y = (fb_config->height)*OK_TEXT_RELATIVE_Y_LOCATION;
+
+	fbcon_clear_section(y, MDTP_PIN_INSTRUCTIONS_HEIGHT);
+}
+
+/**
+ * Display the basic layout of the screen (done only once).
+ */
+static void display_initial_screen(uint32_t pin_length)
+{
+    if (g_initial_screen_displayed == true)
+		return;
+
+    fb_config = fbcon_display();
+
+    if (fb_config)
+	{
+		fbcon_clear();
+
+		if (display_error_message())
+		    display_error_msg();
+		display_initial_delay();
+
+		mdelay(INITIAL_DELAY_MSECONDS);
+
+		g_pin_frames_y_location = ((fb_config->height)*PIN_RELATIVE_Y_LOCATION);
+
+		uint32_t total_pin_length = pin_length*MDTP_PIN_DIGIT_WIDTH + DIGIT_SPACE*(pin_length - 1);
+		uint32_t complete_pin_centered = (fb_config->width - total_pin_length)/2;
+
+		for (int i=0; i<(int)pin_length; i++)
+		{
+			g_pin_frames_x_location[i] = complete_pin_centered + i*(DIGIT_SPACE+MDTP_PIN_DIGIT_WIDTH);
+		}
+
+		for (int i=0; i<(int)pin_length; i++)
+		{
+			display_digit(g_pin_frames_x_location[i], g_pin_frames_y_location, 0);
+		}
+
+		display_ok_button();
+
+		g_initial_screen_displayed = true;
+	}
+	else
+	{
+	    dprintf(CRITICAL,"ERROR: fbcon_config struct is NULL\n");
+	    display_error_msg();
+		return;
+	}
+}
+
+/**
+ * Display the recovery PIN screen and set received buffer
+ * with the PIN the user has entered.
+ * The entered PIN will be validated by the calling function.
+ */
+static void display_get_pin_interface(char *entered_pin, uint32_t pin_length)
+{
+	uint32_t previous_position = 0, current_position = 0;
+
+	display_initial_screen(pin_length);
+	display_enter_pin();
+
+	// Convert ascii to digits
+	for (uint32_t i=0; i<pin_length; i++)
+	{
+		entered_pin[i] -= '0';
+	}
+	display_selected_digit(g_pin_frames_x_location[0], g_pin_frames_y_location, entered_pin[0]);
+	display_digits_instructions();
 
 	while (1)
 	{
-		if(target_volume_down())
+		if (target_volume_up())
 		{
-			display_image_on_screen_RECOVERED();
-			mdelay(MDTP_UX_DELAY);
-			break;
+			// current position is the OK button
+			if (current_position == pin_length)
+			{
+				// Convert digits to ascii and
+				// validate entered PIN in the calling function
+				for (uint32_t i=0; i<pin_length; i++)
+				{
+					entered_pin[i] += '0';
+				}
+				return;
+			}
+
+			// current position is a PIN slot
+			entered_pin[current_position] = (entered_pin[current_position]+1) % 10;
+			display_selected_digit(g_pin_frames_x_location[current_position], g_pin_frames_y_location, entered_pin[current_position]);
+			mdelay(MDTP_PRESSING_DELAY_MSEC);
+		}
+		if (target_volume_down())
+		{
+			previous_position = current_position;
+			current_position = (current_position+1) % (pin_length+1);
+
+			// previous position was the OK button
+			if (previous_position == pin_length)
+			{
+				clear_pin_message();
+				display_ok_button();
+
+				display_digits_instructions();
+				display_selected_digit(g_pin_frames_x_location[current_position], g_pin_frames_y_location, entered_pin[current_position]);
+
+			}
+
+			// current position is the OK button
+			else if (current_position == pin_length)
+			{
+				display_digit(g_pin_frames_x_location[previous_position], g_pin_frames_y_location, entered_pin[previous_position]);
+				clear_digits_instructions();
+
+				display_selected_ok_button();
+				display_pin_instructions();
+			}
+
+			// both the previous and the current positions are PIN slots
+			else
+			{
+				display_digit(g_pin_frames_x_location[previous_position], g_pin_frames_y_location, entered_pin[previous_position]);
+
+				display_selected_digit(g_pin_frames_x_location[current_position], g_pin_frames_y_location, entered_pin[current_position]);
+			}
+
+			mdelay(MDTP_PRESSING_DELAY_MSEC);
 		}
 	}
+}
+
+/*----------------------------------------------------------------------------
+ * External Functions
+ * -------------------------------------------------------------------------*/
+
+/**
+ * Display the recovery PIN screen and set received buffer
+ * with the PIN the user has entered.
+ */
+void get_pin_from_user(char *entered_pin, uint32_t pin_length)
+{
+	display_get_pin_interface(entered_pin, pin_length);
 
 	return;
 }
 
-/* Display the "Verifying Firmware" screen */
-void show_checking_msg()
+/**
+ * User has entered invalid PIN, display error message and
+ * allow the user to try again.
+ */
+void display_invalid_pin_msg()
 {
-	display_image_on_screen_CHECKING();
-	return;
+    clear_pin_message();
+    display_ok_button();
+
+    display_invalid_pin();
+
+    mdelay(INVALID_PIN_DELAY_MSECONDS);
 }
 
-/* Display the "Verifying Firmware" screen */
-void show_recovered_msg()
+/**
+ *  Display error message and stop boot process.
+ */
+void display_error_msg()
 {
-	display_image_on_screen_RECOVERED();
-	return;
+    fbcon_clear();
+	display_error_message();   // No point in checking the return value here
+
+	// Invalid state. Nothing to be done but contacting the OEM.
+	// Stop boot process.
+	dprintf(CRITICAL,"ERROR: blocking boot process\n");
+	while(1)
+	{
+
+	}
 }
 
diff --git a/app/rpmbtests/qseecom_lk_test.c b/app/rpmbtests/qseecom_lk_test.c
new file mode 100644
index 0000000..0bfcb9b
--- /dev/null
+++ b/app/rpmbtests/qseecom_lk_test.c
@@ -0,0 +1,358 @@
+/* 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 <partition_parser.h>
+#include <qseecom_lk.h>
+#include <scm.h>
+
+//#include "qseecom_legacy.h"
+#include "qseecom_lk_api.h"
+#include <debug.h>
+#include <kernel/mutex.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <arch/defines.h>
+#include <string.h>
+
+/* commands supported from sample client */
+#define CLIENT_CMD0_GET_VERSION             0
+#define CLIENT_CMD1_BASIC_DATA              1
+#define CLIENT_CMD2_REGISTER_SB_PTR         2
+#define CLIENT_CMD3_RUN_CRYTPO_TEST         3
+#define CLIENT_CMD4_RUN_CRYTPO_PERF         4
+#define CLIENT_CMD5_RUN_SFS_TEST            5
+#define CLIENT_CMD6_RUN_BUF_ALIGNMENT_TEST  6
+#define CLIENT_CMD7_RUN_CRYPTO_RSA_TEST     7
+#define CLIENT_CMD8_RUN_RSA_PERF_TEST       8
+#define CLIENT_CMD9_RUN_CMNLIB_TEST         9
+#define CLIENT_CMD10_RUN_CORE_TEST          10
+#define CLIENT_CMD11_RUN_SECURECHANNEL_TEST 11
+#define CLIENT_CMD12_RUN_SERVICES_TEST      12
+#define CLIENT_CMD13_RUN_MISC_TEST          13
+#define CLIENT_CMD17_RUN_STORAGE_TEST       17
+#define CLIENT_APPSBL_QSEECOM_RUN_LISTENER_FRAMEWORK_TEST_1       50
+
+#define __64KB__ 0x10000
+#define __32KB__ 0x8000
+#define __16KB__ 0x4000
+#define __8KB__ 0x2000
+#define __4KB__ 0x1000
+#define __2KB__ 0x800
+#define __1KB__ 0x400
+
+#define LISTENER_TEST_SERVICE			0x100
+
+struct qsc_send_cmd {
+     unsigned int cmd_id;
+     unsigned int data;
+     unsigned int data2;
+     unsigned int len;
+     unsigned int start_pkt;
+     unsigned int end_pkt;
+     unsigned int test_buf_size;
+};
+
+struct qsc_send_cmd_rsp {
+  unsigned int data;
+  int status;
+};
+
+
+int listener_test_cmd_handler (void* buf, uint32_t size)
+{
+	uint32 *req = 0;
+	uint32 rsp = 0;
+
+	if ((!buf) || (size < 4)) {
+		dprintf(CRITICAL, "Invalid listener cmd handler inputs\n");
+		return -1;
+	}
+
+	req = (uint32 *)buf;
+	if (*req == (100 * 100)) {
+		dprintf(CRITICAL, "Listener Success\n");
+		rsp = *req * 100;
+		dprintf(CRITICAL, "rsp = %u\n", rsp);
+		memcpy (buf, &rsp, sizeof(uint32));
+		return 0;
+	} else {
+		dprintf(CRITICAL, "Listener Failure, req:%u\n", *req);
+		rsp = 0;
+		memcpy (buf, &rsp, sizeof(uint32));
+		return 0;
+	}
+}
+
+static struct qseecom_listener_services listeners[] = {
+		{
+			.service_name = "Listener Test service",
+			.id = LISTENER_TEST_SERVICE,
+			.sb_size = (20 * 1024),
+			.service_cmd_handler = listener_test_cmd_handler,
+		},
+};
+
+int qsc_run_get_version(char *appname, uint32_t iterations)
+{
+	struct qsc_send_cmd send_cmd;
+	struct qsc_send_cmd_rsp msgrsp={0};	/* response data sent from QSEE */
+	uint32_t i = 0, ret = 0, err = -1;
+
+	dprintf(CRITICAL, "%s:Get_version\n", __func__);
+
+	dprintf(CRITICAL, "(This may take a few minutes please wait....)\n");
+	/* Start the application */
+	for  (i = 0;  i < iterations;  i++) {
+		dprintf(CRITICAL, "iteration %d\n", i);
+		ret = qseecom_start_app(appname);
+		if (ret <= 0) {
+			dprintf(CRITICAL, "Start app: fail: ret:%d\n", ret);
+			err = -1;
+			goto err_ret;
+		}
+		dprintf(CRITICAL, "apphandle %u\n", ret);
+		ret = qseecom_start_app(appname);
+		if (ret <= 0) {
+			dprintf(CRITICAL, "Start app: fail: ret:%d\n", ret);
+			err = -1;
+			goto err_ret_shutdown;
+		}
+		dprintf(CRITICAL, "apphandle %u\n", ret);
+		send_cmd.cmd_id = CLIENT_CMD0_GET_VERSION;
+		err = qseecom_send_command(ret, &send_cmd, sizeof(struct qsc_send_cmd), &msgrsp, sizeof(struct qsc_send_cmd_rsp));
+		if (err) {
+			dprintf(CRITICAL, "Send app: fail\n");
+			goto err_ret_shutdown;
+		}
+		dprintf(ALWAYS, "The version of %s is: %u\n", appname, msgrsp.data);
+		/* Shutdown the application */
+		dprintf(ALWAYS, "Shutting down %s\n", appname);
+		err = qseecom_shutdown_app(ret);
+		if (err) {
+			dprintf(CRITICAL, "Failed to shutdown app: %d\n",err);
+			goto err_ret;
+		}
+		dprintf(ALWAYS, "Shutting down %s\n", appname);
+		err = qseecom_shutdown_app(ret);
+		if (err) {
+			dprintf(CRITICAL, "Failed to shutdown app: %d\n",err);
+			goto err_ret;
+		}
+
+    }
+err_ret_shutdown:
+	if (err) {
+		if (qseecom_shutdown_app(ret))
+			dprintf(CRITICAL, "Failed to shutdown app: %d\n",err);
+	}
+err_ret:
+	if (err)
+		dprintf(CRITICAL, "Test %u failed with error %d, shutting down %s\n", CLIENT_CMD0_GET_VERSION, err, appname);
+	else
+		dprintf(CRITICAL, "Test %u passed for iterations %u executing %s\n", CLIENT_CMD0_GET_VERSION, iterations, appname);
+	return err;
+}
+
+
+int qsc_run_start_stop_app_basic_test(char *appname, uint32_t iterations)
+{
+	uint32_t i = 0;
+	int ret = 0;			/* return value */
+	int err = 0;			/* return value */
+	struct qsc_send_cmd send_cmd = {0};
+	struct qsc_send_cmd_rsp msgrsp={0};	/* response data sent from QSEE */
+
+	dprintf(CRITICAL, "%s:Basic_start_stop_test\n", __func__);
+
+	dprintf(CRITICAL, "(This may take a few minutes please wait....)\n");
+	/* Start the application */
+    for  (i = 0;  i < iterations;  i++) {
+		dprintf(CRITICAL, "iteration %d\n", i);
+		ret = qseecom_start_app(appname);
+		if (ret <= 0) {
+			dprintf(CRITICAL, "Start app: fail: ret:%d\n", ret);
+			err = -1;
+			goto err_ret;
+		}
+		/* Send data using send command to QSEE application */
+		send_cmd.cmd_id = CLIENT_CMD1_BASIC_DATA;
+		send_cmd.start_pkt = 0;
+		send_cmd.end_pkt = 0;
+		send_cmd.test_buf_size = 0;
+		send_cmd.data = 100;
+		err = qseecom_send_command(ret, &send_cmd, sizeof(struct qsc_send_cmd), &msgrsp, sizeof(struct qsc_send_cmd_rsp));
+		if (err) {
+			dprintf(CRITICAL, "Send app: fail\n");
+			goto err_ret_shutdown;
+		}
+		if (((msgrsp.data)/100) != 10) {
+			dprintf(CRITICAL, "App Comm Error:%u\n", msgrsp.data);
+			err = -1;
+			goto err_ret_shutdown;
+		}
+		dprintf(CRITICAL, "msg.rsp:%u\n", msgrsp.data);
+		/* Shutdown the application */
+		err = qseecom_shutdown_app(ret);
+		if (err) {
+			dprintf(CRITICAL, "Failed to shutdown app: %d\n",err);
+			goto err_ret;
+		}
+    }
+err_ret_shutdown:
+    if (err) {
+		if (qseecom_shutdown_app(ret))
+			dprintf(CRITICAL, "Failed to shutdown app: %d\n",err);
+    }
+err_ret:
+	if (err)
+		dprintf(CRITICAL, "Test %u failed with error %d, shutting down %s\n", CLIENT_CMD0_GET_VERSION, err, appname);
+	else
+		dprintf(CRITICAL, "Test %u passed for iterations %u executing %s\n", CLIENT_CMD0_GET_VERSION, iterations, appname);
+		return err;
+}
+
+
+
+int qsc_run_start_stop_app_listener_test(char *appname, uint32_t iterations)
+{
+	uint32_t i = 0;
+	int ret = 0;			/* return value */
+	int err = 0;			/* return value */
+	struct qsc_send_cmd send_cmd;
+	struct qsc_send_cmd_rsp msgrsp={0};	/* response data sent from QSEE */
+
+	dprintf(CRITICAL, "%s:qsc_run_start_stop_app_listener_test\n", __func__);
+
+	dprintf(CRITICAL, "(This may take a few minutes please wait....)\n");
+
+	ret = qseecom_register_listener(&listeners[0]);
+	if (ret < 0) {
+		dprintf(CRITICAL, "Reg Listener: fail: ret:%d\n", ret);
+		err = -1;
+		goto err_ret;
+	}
+	/* Start the application */
+    for  (i = 0;  i < iterations;  i++) {
+		dprintf(CRITICAL, "iteration %d\n", i);
+		ret = qseecom_start_app(appname);
+		if (ret <= 0) {
+			dprintf(CRITICAL, "Start app: fail: ret:%d\n", ret);
+			err = -1;
+			goto err_dereg;
+		}
+		/* Send data using send command to QSEE application */
+		send_cmd.cmd_id = CLIENT_APPSBL_QSEECOM_RUN_LISTENER_FRAMEWORK_TEST_1;
+		send_cmd.start_pkt = 0;
+		send_cmd.end_pkt = 0;
+		send_cmd.test_buf_size = 0;
+		send_cmd.data = 100;
+		err = qseecom_send_command(ret, &send_cmd, sizeof(struct qsc_send_cmd), &msgrsp, sizeof(struct qsc_send_cmd_rsp));
+		if (err) {
+			dprintf(CRITICAL, "Send app: fail\n");
+			goto err_ret_shutdown;
+		}
+		if (((msgrsp.data)/100) != 10) {
+			dprintf(CRITICAL, "App Comm Error:%u Status:%d\n", msgrsp.data, msgrsp.status);
+			err = -1;
+			goto err_ret_shutdown;
+		}
+		/* Shutdown the application */
+		err = qseecom_shutdown_app(ret);
+		if (err) {
+			dprintf(CRITICAL, "Failed to shutdown app: %d\n",err);
+			goto err_dereg;
+		}
+    }
+
+err_ret_shutdown:
+	if (err) {
+	   	if (qseecom_shutdown_app(ret))
+	   		dprintf(CRITICAL, "Failed to shutdown app: %d\n",err);
+	}
+err_dereg:
+	ret = qseecom_deregister_listener(listeners[0].id);
+	if (ret < 0) {
+		dprintf(CRITICAL, "DeReg Listener: fail: ret:%d\n", ret);
+		err = -1;
+	}
+err_ret:
+	if (err)
+		dprintf(CRITICAL, "Test %u failed with error %d, shutting down %s\n", CLIENT_CMD0_GET_VERSION, err, appname);
+	else
+		dprintf(CRITICAL, "Test %u passed for iterations %u executing %s\n", CLIENT_CMD0_GET_VERSION, iterations, appname);
+	return err;
+}
+
+int qseecom_test_cmd_handler(const char *arg) {
+	char *token = NULL;
+	char * appname = NULL;
+	uint32_t test = 0;
+	uint32_t iterations = 0;
+
+	token = strtok((char *)arg, " ");
+	if (!token) {
+		dprintf(CRITICAL, "Appname not provided, error\n");
+		return -1;
+	}
+	appname = token;
+
+	token = strtok(NULL, " ");
+	if (!token) {
+		dprintf(CRITICAL, "Test not provided, error\n");
+		return -1;
+	}
+	test = atoi(token);
+
+	token = strtok(NULL, " ");
+	if (token)
+		iterations = atoi(token);
+	else
+		dprintf(CRITICAL, "iterations not provided\n");
+
+	switch (test) {
+		case CLIENT_CMD0_GET_VERSION:
+		{
+			qsc_run_get_version(appname, iterations);
+			break;
+		}
+		case CLIENT_CMD1_BASIC_DATA:
+		{
+			qsc_run_start_stop_app_basic_test(appname, iterations);
+			break;
+		}
+
+		case CLIENT_APPSBL_QSEECOM_RUN_LISTENER_FRAMEWORK_TEST_1:
+		{
+			qsc_run_start_stop_app_listener_test(appname, iterations);
+			break;
+		}
+	}
+	dprintf(CRITICAL, "test:%u iterations:%u\n", test, iterations);
+	return 0;
+}
+
diff --git a/app/rpmbtests/rules.mk b/app/rpmbtests/rules.mk
index b59dee9..f43c488 100644
--- a/app/rpmbtests/rules.mk
+++ b/app/rpmbtests/rules.mk
@@ -5,4 +5,5 @@
 DEFINES += ASSERT_ON_TAMPER=1
 
 OBJS += \
-	$(LOCAL_DIR)/ufs_rpmb.o
+	$(LOCAL_DIR)/ufs_rpmb.o \
+	$(LOCAL_DIR)/qseecom_lk_test.o
diff --git a/app/rpmbtests/ufs_rpmb.c b/app/rpmbtests/ufs_rpmb.c
index 7342a82..d951933 100644
--- a/app/rpmbtests/ufs_rpmb.c
+++ b/app/rpmbtests/ufs_rpmb.c
@@ -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
@@ -99,9 +99,11 @@
 	}
 	memset(&data_frame, 0, sizeof(data_frame));
 	memset(&result_frame, 0, sizeof(result_frame));
-	data_frame.address = BE16(address);
-	data_frame.blockcount = BE16(rpmb_num_blocks);
-	data_frame.requestresponse = BE16(AUTH_READ);
+	data_frame.address[0] = (address & 0xff00) >> 8;
+	data_frame.address[1] = address & 0x00ff;
+	data_frame.blockcount[0] = (rpmb_num_blocks & 0xff00) >> 8;
+	data_frame.blockcount[1] = rpmb_num_blocks & 0x00ff;
+	data_frame.requestresponse[1] = AUTH_READ;
 	for(i = 0 ; i < 16; i++)
 	{
 		data_frame.nonce[i] = (rand() % 256) + 1;
diff --git a/dev/gcdb/display/include/panel_jdi_a216_fhd_video.h b/dev/gcdb/display/include/panel_jdi_a216_fhd_video.h
index 6f09f38..484edac 100755
--- a/dev/gcdb/display/include/panel_jdi_a216_fhd_video.h
+++ b/dev/gcdb/display/include/panel_jdi_a216_fhd_video.h
@@ -85,15 +85,28 @@
 	0x11, 0x00, 0x05, 0x80
 };
 
+static char jdi_a216_fhd_video_on_cmd5[] = {
+	0xB0, 0x04, 0x29, 0x80
+};
+
+static char jdi_a216_fhd_video_on_cmd6[] = {
+	0x06, 0x00, 0x29, 0xC0,
+	0xD0, 0x10, 0x93, 0xBB,
+	0x12, 0x8E, 0xFF, 0xFF
+};
+
+
 static struct mipi_dsi_cmd jdi_a216_fhd_video_on_command[] = {
 	{0x4, jdi_a216_fhd_video_on_cmd0, 0x0a},
 	{0x4, jdi_a216_fhd_video_on_cmd1, 0x0a},
 	{0x4, jdi_a216_fhd_video_on_cmd2, 0x0a},
 	{0x4, jdi_a216_fhd_video_on_cmd3, 0x28},
 	{0x4, jdi_a216_fhd_video_on_cmd4, 0xc8},
+	{0x4, jdi_a216_fhd_video_on_cmd5, 0x0a},
+	{0xc, jdi_a216_fhd_video_on_cmd6, 0x0a}
 };
 
-#define JDI_A216_FHD_VIDEO_ON_COMMAND 5
+#define JDI_A216_FHD_VIDEO_ON_COMMAND 7
 
 
 static char jdi_a216_fhd_videooff_cmd0[] = {
@@ -113,7 +126,7 @@
 
 
 static struct command_state jdi_a216_fhd_video_state = {
-	0, 1
+	1, 1
 };
 
 /*---------------------------------------------------------------------------*/
diff --git a/platform/msm_shared/include/qseecom_lk.h b/platform/msm_shared/include/qseecom_lk.h
new file mode 100644
index 0000000..dd130ed
--- /dev/null
+++ b/platform/msm_shared/include/qseecom_lk.h
@@ -0,0 +1,164 @@
+/* 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.
+ */
+
+#ifndef _QSEECOM_LK_H_
+#define _QSEECOM_LK_H_
+
+#define MAX_APP_NAME_SIZE  32
+#define QSEECOM_HASH_SIZE  32
+
+/* TZ Diagnostic Area legacy version number */
+#define TZBSP_DIAG_MAJOR_VERSION_LEGACY 2
+
+/*
+ * Log ring buffer position
+ */
+struct tzdbg_log_pos_t {
+	uint16_t wrap;
+	uint16_t offset;
+};
+
+ /*
+ * Log ring buffer
+ */
+struct tzdbg_log_t {
+	struct tzdbg_log_pos_t log_pos;
+	/* open ended array to the end of the 4K IMEM buffer */
+	uint8_t log_buf[];
+};
+struct scm_desc {
+	uint32_t arginfo;
+	uint32_t args[10];
+	uint32_t ret[3];
+	/* private */
+	void *extra_arg_buf;
+	uint64_t x5;
+};
+/*
+ * struct qseecom_register_listener_req -
+ *      for register listener ioctl request
+ * @listener_id - service id (shared between userspace and QSE)
+ * @ifd_data_fd - ion handle
+ * @virt_sb_base - shared buffer base in user space
+ * @sb_size - shared buffer size
+ */
+struct qseecom_register_listener_req {
+	uint32_t listener_id; /* in */
+	void *virt_sb_base; /* in */
+	uint32_t sb_size; /* in */
+};
+
+/*
+ * struct qseecom_send_cmd_req - for send command ioctl request
+ * @cmd_req_len - command buffer length
+ * @cmd_req_buf - command buffer
+ * @resp_len - response buffer length
+ * @resp_buf - response buffer
+ */
+struct qseecom_send_cmd_req {
+	void *cmd_req_buf; /* in */
+	unsigned int cmd_req_len; /* in */
+	void *resp_buf; /* in/out */
+	unsigned int resp_len; /* in/out */
+};
+
+/*
+ * struct qseecom_ion_fd_info - ion fd handle data information
+ * @fd - ion handle to some memory allocated in user space
+ * @cmd_buf_offset - command buffer offset
+ */
+struct qseecom_ion_fd_info {
+	int32_t fd;
+	uint32_t cmd_buf_offset;
+};
+
+/*
+ * struct qseecom_listener_send_resp_req - signal to continue the send_cmd req.
+ * Used as a trigger from HLOS service to notify QSEECOM that it's done with its
+ * operation and provide the response for QSEECOM can continue the incomplete
+ * command execution
+ * @resp_len - Length of the response
+ * @resp_buf - Response buffer where the response of the cmd should go.
+ */
+struct qseecom_send_resp_req {
+	void *resp_buf; /* in */
+	unsigned int resp_len; /* in */
+};
+
+/*
+ * struct qseecom_load_img_data - for sending image length information and
+ * ion file descriptor to the qseecom driver. ion file descriptor is used
+ * for retrieving the ion file handle and in turn the physical address of
+ * the image location.
+ * @mdt_len - Length of the .mdt file in bytes.
+ * @img_len - Length of the .mdt + .b00 +..+.bxx images files in bytes
+ * @ion_fd - Ion file descriptor used when allocating memory.
+ * @img_name - Name of the image.
+*/
+struct qseecom_load_img_req {
+	uint32_t mdt_len; /* in */
+	uint32_t img_len; /* in */
+	int32_t  ifd_data_fd; /* in */
+	char  img_name[MAX_APP_NAME_SIZE]; /* in */
+	int app_id; /* out*/
+};
+
+struct qseecom_set_sb_mem_param_req {
+	int32_t ifd_data_fd; /* in */
+	void *virt_sb_base; /* in */
+	uint32_t sb_len; /* in */
+};
+
+/*
+ * struct qseecom_qseos_version_req - get qseos version
+ * @qseos_version - version number
+ */
+struct qseecom_qseos_version_req {
+	unsigned int qseos_version; /* in */
+};
+
+/*
+ * struct qseecom_qseos_app_load_query - verify if app is loaded in qsee
+ * @app_name[MAX_APP_NAME_SIZE]-  name of the app.
+ * @app_id - app id.
+ */
+struct qseecom_qseos_app_load_query {
+	char app_name[MAX_APP_NAME_SIZE]; /* in */
+	int app_id; /* out */
+};
+
+struct qseecom_send_svc_cmd_req {
+	uint32_t cmd_id;
+	void *cmd_req_buf; /* in */
+	unsigned int cmd_req_len; /* in */
+	void *resp_buf; /* in/out */
+	unsigned int resp_len; /* in/out */
+};
+
+
+#endif /* _QSEECOM_LK_H_ */
diff --git a/platform/msm_shared/include/qseecom_lk_api.h b/platform/msm_shared/include/qseecom_lk_api.h
new file mode 100644
index 0000000..c26da9b
--- /dev/null
+++ b/platform/msm_shared/include/qseecom_lk_api.h
@@ -0,0 +1,189 @@
+/* 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.
+ */
+
+#ifndef __QSEECOM_LK_API_H_
+#define __QSEECOM_LK_API_H_
+
+#define MAX_APP_NAME_LEN 32
+
+#include <stdint.h>
+/**
+* Qseecom Init
+*	To be called before any calls to qsee secure apps.
+*
+* @return int
+*   Success:	Init succeeded.
+*   Failure:	Error code (negative only).
+*/
+int qseecom_init();
+
+/**
+* Qseecom Tz Init
+*	To be called before any calls to qsee secure apps.
+*
+* @return int
+*   Success:	Tz init succeeded.
+*   Failure:	Error code (negative only).
+*/
+int qseecom_tz_init();
+
+/**
+* Qseecom Exit
+*	To be called before exit of lk.
+*	Once this is called no calls to
+*	Qsee Apps.
+*
+* @return int
+*   Success:	Exit succeeded.
+*   Failure:	Error code (negative only).
+*/
+int qseecom_exit();
+
+/**
+* Start a Secure App
+*
+* @param char* app_name
+*   App name of the Secure App to be started
+*   The app_name provided should be the same
+*   name as the partition/ file and should
+*   be the same name mentioned in TZ_APP_NAME
+*   in the secure app.
+*
+* @return int
+*   Success:	handle to be used for all calls to
+*   			Secure app. Always greater than zero.
+*   Failure:	Error code (negative only).
+*/
+int qseecom_start_app(char *app_name);
+
+/**
+* Shutdown a Secure App
+*
+* @param int handle
+*   Handle  of the Secure App to be shutdown
+*
+* @return int
+*   Status:
+*     0 - Success
+*     Negative value indicates failure.
+*/
+int qseecom_shutdown_app(int handle);
+
+/**
+* Shutdown a Secure App
+*
+* @param int handle
+*   Handle  of the Secure App to send the cmd
+*
+* @param void *send_buf
+*   Pointer to the App request buffer
+*
+* @param uint32_t sbuf_len
+*   Size of the request buffer
+*
+* @param void *resp_buf
+*   Pointer to the App response buffer
+*
+* @param uint32_t rbuf_len
+*   Size of the response buffer
+*
+* @return int
+*   Status:
+*     0 - Success
+*     Negative value indicates failure.
+*/
+int qseecom_send_command(int handle, void *send_buf,
+			uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len);
+
+typedef int (*ListenerCallback)(void*, uint32_t);
+
+/**
+ * @param char* service_name
+ * 	 The name of the listener service.
+ * @param uint32_t  id
+ * 	 The id used to register a listener with
+ * 	 QSEE in the secure side. This id should
+ * 	 be unique.
+ * @param ListenerCallback service_cmd_handler
+ *   This is the service cmd handler, this cb
+ *   is called for a specific service request.
+ *   The input params are,
+ * 		@param void *buf
+ * 		  The shared buffer which contains the
+ * 		  request from the secure side. The service
+ * 		  also updates this buffer with the response.
+ * 		@param uint32_t size
+ * 		  The size of the shared buffer.
+ *      @return int
+ *        Success:	Exit succeeded.
+ *        Failure:	Error code (negative only).
+ */
+struct qseecom_listener_services {
+	char *service_name;
+	uint32_t  id;
+	uint32_t sb_size;
+	ListenerCallback service_cmd_handler;
+};
+
+/**
+* Registers a Listener Service with QSEE
+*  This api should be called after all
+*  service specific initialization is
+*  completed, once this is called the
+*  service_cmd_handler for the service can
+*  be called.
+*
+* @param struct qseecom_listener_services listnr
+*   Listener structure that contains all the info
+*   to register a listener service.
+*
+* @return int
+*   Status:
+*     0 - Success
+*     Negative value indicates failure.
+*/
+int qseecom_register_listener(struct qseecom_listener_services *listnr);
+
+/**
+* De-Registers a Listener Service with QSEE
+*  This api should be called before exiting lk and
+*  all service de-init should be done before calling
+*  the api. service_cmd_handler will not be called
+*  after this api is called.
+*
+* @param uint32_t listnr_id
+*   Pre-defined Listener ID to be de-registered
+*
+* @return int
+*   Status:
+*     0 - Success
+*     Negative value indicates failure.
+*/
+int qseecom_deregister_listener(uint32_t listnr_id);
+
+#endif /* __QSEECOM_API_LK_H_ */
diff --git a/platform/msm_shared/include/qseecomi_lk.h b/platform/msm_shared/include/qseecomi_lk.h
new file mode 100644
index 0000000..ee442be
--- /dev/null
+++ b/platform/msm_shared/include/qseecomi_lk.h
@@ -0,0 +1,518 @@
+/* Copyright (c) 2013-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
+ * 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.
+ */
+
+#ifndef __QSEECOMI_LK_H_
+#define __QSEECOMI_LK_H_
+
+#include <qseecom_lk.h>
+
+#define QSEECOM_KEY_ID_SIZE   32
+
+#define QSEOS_RESULT_FAIL_UNSUPPORTED_CE_PIPE -63
+#define QSEOS_RESULT_FAIL_KS_OP               -64
+#define QSEOS_RESULT_FAIL_KEY_ID_EXISTS       -65
+#define QSEOS_RESULT_FAIL_MAX_KEYS            -66
+#define QSEOS_RESULT_FAIL_SAVE_KS             -67
+#define QSEOS_RESULT_FAIL_LOAD_KS             -68
+#define QSEOS_RESULT_FAIL_KS_ALREADY_DONE     -69
+#define QSEOS_RESULT_FAIL_KEY_ID_DNE          -70
+#define QSEOS_RESULT_FAIL_INCORRECT_PSWD      -71
+#define QSEOS_RESULT_FAIL_MAX_ATTEMPT         -72
+
+enum qseecom_command_scm_resp_type {
+	QSEOS_APP_ID = 0xEE01,
+	QSEOS_LISTENER_ID
+};
+
+typedef enum
+{
+  QSEE_APP_START_COMMAND = 0x01,
+  QSEE_APP_SHUTDOWN_COMMAND,
+  QSEE_APP_LOOKUP_COMMAND,
+  QSEE_REGISTER_LISTENER,
+  QSEE_DEREGISTER_LISTENER,
+  QSEE_CLIENT_SEND_DATA_COMMAND,
+  QSEE_LISTENER_DATA_RSP_COMMAND,
+  QSEE_LOAD_EXTERNAL_ELF_COMMAND,
+  QSEE_UNLOAD_EXTERNAL_ELF_COMMAND,
+  QSEE_GET_APP_STATE_COMMAND,
+  QSEE_LOAD_SERV_IMAGE_COMMAND,
+  QSEE_UNLOAD_SERV_IMAGE_COMMAND,
+  QSEE_APP_REGION_NOTIFICATION,
+  QSEE_REGISTER_LOG_BUF_COMMAND,
+  QSEE_RPMB_PROVISION_KEY_COMMAND,
+  QSEE_RPMB_ERASE_COMMAND,
+  QSEE_KS_GEN_KEY_COMMAND,
+  QSEE_KS_DEL_KEY_COMMAND,
+  QSEE_KS_GET_MAX_KEYS_COMMAND,
+  QSEE_KS_SET_PIPE_KEY_COMMAND,
+  QSEE_KS_UPDATE_KEY_COMMAND,
+  QSEE_GP_OPEN_SESSION,
+  QSEE_GP_INVOKE_COMMAND,
+  QSEE_GP_CLOSE_SESSION,
+}qsee_smc_command_type;
+
+enum qseecom_qceos_cmd_status {
+	QSEOS_RESULT_SUCCESS = 0,
+	QSEOS_RESULT_INCOMPLETE,
+	QSEOS_RESULT_FAILURE  = 0xFFFFFFFF
+};
+
+enum qseecom_pipe_type {
+	QSEOS_PIPE_ENC = 0x1,
+	QSEOS_PIPE_ENC_XTS = 0x2,
+	QSEOS_PIPE_AUTH = 0x4,
+	QSEOS_PIPE_ENUM_FILL = 0x7FFFFFFF
+};
+
+struct __attribute__ ((packed)) qsee_apps_region_info_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t addr;
+	uint32_t size;
+};
+
+struct __attribute__ ((packed)) qseecom_check_app_ireq {
+	uint32_t qsee_cmd_id;
+	char     app_name[MAX_APP_NAME_SIZE];
+};
+
+struct __attribute__ ((packed)) qseecom_load_app_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t mdt_len;		/* Length of the mdt file */
+	uint32_t img_len;		/* Length of .bxx and .mdt files */
+	uint32_t phy_addr;		/* phy addr of the start of image */
+	char     app_name[MAX_APP_NAME_SIZE];	/* application name*/
+};
+
+struct __attribute__ ((packed)) qseecom_unload_app_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t  app_id;
+};
+
+struct __attribute__ ((packed)) qseecom_load_lib_image_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t mdt_len;
+	uint32_t img_len;
+	uint32_t phy_addr;
+};
+
+struct __attribute__ ((packed)) qseecom_unload_lib_image_ireq {
+	uint32_t qsee_cmd_id;
+};
+
+struct __attribute__ ((packed)) qseecom_register_listener_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t listener_id;
+	uint32_t sb_ptr;
+	uint32_t sb_len;
+};
+
+struct __attribute__ ((packed)) qseecom_unregister_listener_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t  listener_id;
+};
+
+struct __attribute__ ((packed)) qseecom_client_send_data_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t app_id;
+	uint32_t req_ptr;
+	uint32_t req_len;
+	uint32_t rsp_ptr;/* First 4 bytes should be the return status */
+	uint32_t rsp_len;
+};
+
+struct __attribute__ ((packed)) qseecom_reg_log_buf_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t phy_addr;
+	uint32_t len;
+};
+
+/* send_data resp */
+struct __attribute__ ((packed)) qseecom_client_listener_data_irsp {
+	uint32_t qsee_cmd_id;
+	uint32_t listener_id;
+	uint32_t status;
+};
+
+/*
+ * struct qseecom_command_scm_resp - qseecom response buffer
+ * @cmd_status: value from enum tz_sched_cmd_status
+ * @sb_in_rsp_addr: points to physical location of response
+ *                buffer
+ * @sb_in_rsp_len: length of command response
+ */
+struct __attribute__ ((packed)) qseecom_command_scm_resp {
+	uint32_t result;
+	enum qseecom_command_scm_resp_type resp_type;
+	unsigned int data;
+};
+
+struct qseecom_rpmb_provision_key {
+	uint32_t key_type;
+};
+
+struct __attribute__ ((packed)) qseecom_client_send_service_ireq {
+	uint32_t qsee_cmd_id;
+	uint32_t key_type; /* in */
+	unsigned int req_len; /* in */
+	uint32_t rsp_ptr; /* in/out */
+	unsigned int rsp_len; /* in/out */
+};
+
+struct __attribute__ ((packed)) qseecom_key_generate_ireq {
+	uint32_t qsee_command_id;
+	uint32_t flags;
+	uint8_t key_id[QSEECOM_KEY_ID_SIZE];
+	uint8_t hash32[QSEECOM_HASH_SIZE];
+};
+
+struct __attribute__ ((packed)) qseecom_key_select_ireq {
+	uint32_t qsee_command_id;
+	uint32_t ce;
+	uint32_t pipe;
+	uint32_t pipe_type;
+	uint32_t flags;
+	uint8_t key_id[QSEECOM_KEY_ID_SIZE];
+	uint8_t hash32[QSEECOM_HASH_SIZE];
+};
+
+struct __attribute__ ((packed)) qseecom_key_delete_ireq {
+	uint32_t qsee_command_id;
+	uint32_t flags;
+	uint8_t key_id[QSEECOM_KEY_ID_SIZE];
+	uint8_t hash32[QSEECOM_HASH_SIZE];
+
+};
+
+struct __attribute__ ((packed)) qseecom_key_userinfo_update_ireq {
+	uint32_t qsee_command_id;
+	uint32_t flags;
+	uint8_t key_id[QSEECOM_KEY_ID_SIZE];
+	uint8_t current_hash32[QSEECOM_HASH_SIZE];
+	uint8_t new_hash32[QSEECOM_HASH_SIZE];
+};
+
+struct __attribute__ ((packed)) qseecom_key_max_count_query_ireq {
+	uint32_t flags;
+};
+
+struct __attribute__ ((packed)) qseecom_key_max_count_query_irsp {
+	uint32_t max_key_count;
+};
+
+struct __attribute__ ((packed)) qseecom_qteec_ireq {
+	uint32_t    qsee_cmd_id;
+	uint32_t    app_id;
+	uint32_t    req_ptr;
+	uint32_t    req_len;
+	uint32_t    resp_ptr;
+	uint32_t    resp_len;
+};
+
+struct __attribute__ ((packed)) qseecom_client_send_fsm_key_req {
+	uint32_t qsee_cmd_id;
+	uint32_t req_ptr;
+	uint32_t req_len;
+	uint32_t rsp_ptr;
+	uint32_t rsp_len;
+};
+
+
+/**********      ARMV8 SMC INTERFACE TZ MACRO     *******************/
+
+#define TZ_SVC_APP_MGR                   1     /* Application management */
+#define TZ_SVC_LISTENER                  2     /* Listener service management */
+#define TZ_SVC_EXTERNAL                  3     /* External image loading */
+#define TZ_SVC_RPMB                      4     /* RPMB */
+#define TZ_SVC_KEYSTORE                  5     /* Keystore management */
+#define TZ_SVC_ES                        16    /* Enterprise Security */
+
+/*----------------------------------------------------------------------------
+ * Owning Entity IDs (defined by ARM SMC doc)
+ * -------------------------------------------------------------------------*/
+#define TZ_OWNER_ARM                     0     /** ARM Architecture call ID */
+#define TZ_OWNER_CPU                     1     /** CPU service call ID */
+#define TZ_OWNER_SIP                     2     /** SIP service call ID */
+#define TZ_OWNER_OEM                     3     /** OEM service call ID */
+#define TZ_OWNER_STD                     4     /** Standard service call ID */
+
+/** Values 5-47 are reserved for future use */
+
+/** Trusted Application call IDs */
+#define TZ_OWNER_TZ_APPS                 48
+#define TZ_OWNER_TZ_APPS_RESERVED        49
+/** Trusted OS Call IDs */
+#define TZ_OWNER_QSEE_OS                 50
+#define TZ_OWNER_MOBI_OS                 51
+#define TZ_OWNER_OS_RESERVED_3           52
+#define TZ_OWNER_OS_RESERVED_4           53
+#define TZ_OWNER_OS_RESERVED_5           54
+#define TZ_OWNER_OS_RESERVED_6           55
+#define TZ_OWNER_OS_RESERVED_7           56
+#define TZ_OWNER_OS_RESERVED_8           57
+#define TZ_OWNER_OS_RESERVED_9           58
+#define TZ_OWNER_OS_RESERVED_10          59
+#define TZ_OWNER_OS_RESERVED_11          60
+#define TZ_OWNER_OS_RESERVED_12          61
+#define TZ_OWNER_OS_RESERVED_13          62
+#define TZ_OWNER_OS_RESERVED_14          63
+
+#define TZ_SVC_INFO                      6     /* Misc. information services */
+
+/** Trusted Application call groups */
+#define TZ_SVC_APP_ID_PLACEHOLDER        0     /* SVC bits will contain App ID */
+
+/** General helper macro to create a bitmask from bits low to high. */
+#define TZ_MASK_BITS(h, l)     ((0xffffffff >> (32 - ((h - l) + 1))) << l)
+
+/**
+   Macro used to define an SMC ID based on the owner ID,
+   service ID, and function number.
+*/
+#define TZ_SYSCALL_CREATE_SMC_ID(o, s, f) \
+	((uint32_t)((((o & 0x3f) << 24) | (s & 0xff) << 8) | (f & 0xff)))
+
+#define TZ_SYSCALL_PARAM_NARGS_MASK  TZ_MASK_BITS(3, 0)
+#define TZ_SYSCALL_PARAM_TYPE_MASK   TZ_MASK_BITS(1, 0)
+
+#define TZ_SYSCALL_CREATE_PARAM_ID(nargs, p1, p2, p3, \
+	p4, p5, p6, p7, p8, p9, p10) \
+	((nargs&TZ_SYSCALL_PARAM_NARGS_MASK)+ \
+	((p1&TZ_SYSCALL_PARAM_TYPE_MASK)<<4)+ \
+	((p2&TZ_SYSCALL_PARAM_TYPE_MASK)<<6)+ \
+	((p3&TZ_SYSCALL_PARAM_TYPE_MASK)<<8)+ \
+	((p4&TZ_SYSCALL_PARAM_TYPE_MASK)<<10)+ \
+	((p5&TZ_SYSCALL_PARAM_TYPE_MASK)<<12)+ \
+	((p6&TZ_SYSCALL_PARAM_TYPE_MASK)<<14)+ \
+	((p7&TZ_SYSCALL_PARAM_TYPE_MASK)<<16)+ \
+	((p8&TZ_SYSCALL_PARAM_TYPE_MASK)<<18)+ \
+	((p9&TZ_SYSCALL_PARAM_TYPE_MASK)<<20)+ \
+	((p10&TZ_SYSCALL_PARAM_TYPE_MASK)<<22))
+
+/**
+   Macros used to create the Parameter ID associated with the syscall
+ */
+#define TZ_SYSCALL_CREATE_PARAM_ID_0 0
+#define TZ_SYSCALL_CREATE_PARAM_ID_1(p1) \
+	TZ_SYSCALL_CREATE_PARAM_ID(1, p1, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+#define TZ_SYSCALL_CREATE_PARAM_ID_2(p1, p2) \
+	TZ_SYSCALL_CREATE_PARAM_ID(2, p1, p2, 0, 0, 0, 0, 0, 0, 0, 0)
+#define TZ_SYSCALL_CREATE_PARAM_ID_3(p1, p2, p3) \
+	TZ_SYSCALL_CREATE_PARAM_ID(3, p1, p2, p3, 0, 0, 0, 0, 0, 0, 0)
+#define TZ_SYSCALL_CREATE_PARAM_ID_4(p1, p2, p3, p4) \
+	TZ_SYSCALL_CREATE_PARAM_ID(4, p1, p2, p3, p4, 0, 0, 0, 0, 0, 0)
+#define TZ_SYSCALL_CREATE_PARAM_ID_5(p1, p2, p3, p4, p5) \
+	TZ_SYSCALL_CREATE_PARAM_ID(5, p1, p2, p3, p4, p5, 0, 0, 0, 0, 0)
+#define TZ_SYSCALL_CREATE_PARAM_ID_6(p1, p2, p3, p4, p5, p6) \
+	TZ_SYSCALL_CREATE_PARAM_ID(6, p1, p2, p3, p4, p5, p6, 0, 0, 0, 0)
+#define TZ_SYSCALL_CREATE_PARAM_ID_7(p1, p2, p3, p4, p5, p6, p7) \
+	TZ_SYSCALL_CREATE_PARAM_ID(7, p1, p2, p3, p4, p5, p6, p7, 0, 0, 0)
+#define TZ_SYSCALL_CREATE_PARAM_ID_8(p1, p2, p3, p4, p5, p6, p7, p8) \
+	TZ_SYSCALL_CREATE_PARAM_ID(8, p1, p2, p3, p4, p5, p6, p7, p8, 0, 0)
+#define TZ_SYSCALL_CREATE_PARAM_ID_9(p1, p2, p3, p4, p5, p6, p7, p8, p9) \
+	TZ_SYSCALL_CREATE_PARAM_ID(9, p1, p2, p3, p4, p5, p6, p7, p8, p9, 0)
+#define TZ_SYSCALL_CREATE_PARAM_ID_10(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) \
+	TZ_SYSCALL_CREATE_PARAM_ID(10, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
+
+/**
+   Macro used to obtain the Parameter ID associated with the syscall
+ */
+#define TZ_SYSCALL_GET_PARAM_ID(CMD_ID)        CMD_ID ## _PARAM_ID
+
+#define TZ_SYSCALL_PARAM_TYPE_VAL              0x0     /** type of value */
+#define TZ_SYSCALL_PARAM_TYPE_BUF_RO           0x1     /** type of buffer read-only */
+#define TZ_SYSCALL_PARAM_TYPE_BUF_RW           0x2     /** type of buffer read-write */
+
+#define TZ_OS_APP_START_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_APP_MGR, 0x01)
+
+#define TZ_OS_APP_START_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_3( \
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_VAL, \
+	TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_APP_SHUTDOWN_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_APP_MGR, 0x02)
+
+#define TZ_OS_APP_SHUTDOWN_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_1(TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_APP_LOOKUP_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_APP_MGR, 0x03)
+
+#define TZ_OS_APP_LOOKUP_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_2( \
+	TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_APP_GET_STATE_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_APP_MGR, 0x04)
+
+#define TZ_OS_APP_GET_STATE_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_1(TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_APP_REGION_NOTIFICATION_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_APP_MGR, 0x05)
+
+#define TZ_OS_APP_REGION_NOTIFICATION_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_2( \
+	TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_REGISTER_LOG_BUFFER_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_APP_MGR, 0x06)
+
+#define TZ_OS_REGISTER_LOG_BUFFER_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_2( \
+	TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_LOAD_SERVICES_IMAGE_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_APP_MGR, 0x07)
+
+#define TZ_OS_LOAD_SERVICES_IMAGE_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_3( \
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_VAL, \
+	TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_UNLOAD_SERVICES_IMAGE_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_APP_MGR, 0x08)
+
+#define TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_0
+
+#define TZ_OS_REGISTER_LISTENER_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_LISTENER, 0x01)
+
+#define TZ_OS_REGISTER_LISTENER_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_3( \
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
+	TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_DEREGISTER_LISTENER_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_LISTENER, 0x02)
+
+#define TZ_OS_DEREGISTER_LISTENER_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_1(TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_LISTENER_RESPONSE_HANDLER_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_LISTENER, 0x03)
+
+#define TZ_OS_LISTENER_RESPONSE_HANDLER_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_2( \
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_LOAD_EXTERNAL_IMAGE_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_EXTERNAL, 0x01)
+
+#define TZ_OS_LOAD_EXTERNAL_IMAGE_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_3( \
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_VAL, \
+	TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_APP_QSAPP_SEND_DATA_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_TZ_APPS, \
+	TZ_SVC_APP_ID_PLACEHOLDER, 0x01)
+
+
+#define TZ_APP_QSAPP_SEND_DATA_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_5( \
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
+	TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_UNLOAD_EXTERNAL_IMAGE_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_EXTERNAL, 0x02)
+
+#define TZ_OS_UNLOAD_EXTERNAL_IMAGE_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_0
+
+#define TZ_INFO_IS_SVC_AVAILABLE_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, TZ_SVC_INFO, 0x01)
+
+#define TZ_INFO_IS_SVC_AVAILABLE_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_1(TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_INFO_GET_FEATURE_VERSION_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, TZ_SVC_INFO, 0x03)
+
+#define TZ_INFO_GET_FEATURE_VERSION_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_1(TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_RPMB_PROVISION_KEY_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_RPMB, 0x01)
+
+#define TZ_OS_RPMB_PROVISION_KEY_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_1(TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_RPMB_ERASE_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_RPMB, 0x02)
+
+#define TZ_OS_RPMB_ERASE_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_0
+
+#define TZ_OS_KS_GEN_KEY_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_KEYSTORE, 0x01)
+
+#define TZ_OS_KS_GEN_KEY_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_2( \
+	TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_KS_DEL_KEY_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_KEYSTORE, 0x02)
+
+#define TZ_OS_KS_DEL_KEY_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_2( \
+	TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_KS_GET_MAX_KEYS_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_KEYSTORE, 0x03)
+
+#define TZ_OS_KS_GET_MAX_KEYS_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_1(TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_KS_SET_PIPE_KEY_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_KEYSTORE, 0x04)
+
+#define TZ_OS_KS_SET_PIPE_KEY_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_2( \
+	TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_OS_KS_UPDATE_KEY_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_KEYSTORE, 0x05)
+
+#define TZ_OS_KS_UPDATE_KEY_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_2( \
+	TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#define TZ_ES_SAVE_PARTITION_HASH_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, TZ_SVC_ES, 0x01)
+
+#define TZ_ES_SAVE_PARTITION_HASH_ID_PARAM_ID \
+	TZ_SYSCALL_CREATE_PARAM_ID_3( \
+	TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
+	TZ_SYSCALL_PARAM_TYPE_VAL)
+
+#endif /* __QSEECOMI_LK_H_ */
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/include/scm.h b/platform/msm_shared/include/scm.h
index 83685d5..06f6c6a 100644
--- a/platform/msm_shared/include/scm.h
+++ b/platform/msm_shared/include/scm.h
@@ -318,6 +318,10 @@
 int scm_svc_get_secure_state(uint32_t *state_low, uint32_t *state_high);
 
 int scm_protect_keystore(uint32_t * img_ptr, uint32_t  img_len);
+int
+scm_call(uint32_t svc_id, uint32_t cmd_id, const void *cmd_buf,
+        size_t cmd_len, void *resp_buf, size_t resp_len);
+
 
 #define SCM_SVC_FUSE                0x08
 #define SCM_BLOW_SW_FUSE_ID         0x01
@@ -342,6 +346,7 @@
 
 #define SCM_SVC_MILESTONE_32_64_ID      0x1
 #define SCM_SVC_MILESTONE_CMD_ID        0xf
+#define SCM_SVC_TZSCHEDULER             0xFC
 
 enum ap_ce_channel_type {
 AP_CE_REGISTER_USE = 0,
@@ -451,4 +456,7 @@
  */
 void scm_init();
 bool is_secure_boot_enable();
+
+/* Is armv8 supported */
+bool is_scm_armv8_support();
 #endif
diff --git a/platform/msm_shared/include/ucs.h b/platform/msm_shared/include/ucs.h
index 48c50db..a512955 100644
--- a/platform/msm_shared/include/ucs.h
+++ b/platform/msm_shared/include/ucs.h
@@ -29,6 +29,8 @@
 #ifndef _UCS_H
 #define _UCS_H
 
+#include <upiu.h>
+
 #define SCSI_MAX_DATA_TRANS_BLK_LEN    0xFFFF
 #define UFS_DEFAULT_SECTORE_SIZE       4096
 
@@ -43,10 +45,6 @@
 #define SCSI_SEC_PROT                  0xEC
 #define SCSI_SEC_UFS_PROT_ID           0x0001
 
-#define RPMB_BLK_SIZE                  512
-#define RPMB_FRAME_SIZE                512
-#define RPMB_MIN_BLK_CNT               1
-
 /* FLAGS for indication of read or write */
 enum scsi_upiu_flags
 {
@@ -163,6 +161,7 @@
 }__PACKED;
 
 int ucs_scsi_send_inquiry(struct ufs_dev *dev);
+int ucs_do_scsi_cmd(struct ufs_dev *dev, struct scsi_req_build_type *req);
 int ucs_do_scsi_read(struct ufs_dev *dev, struct scsi_rdwr_req *req);
 int ucs_do_scsi_write(struct ufs_dev *dev, struct scsi_rdwr_req *req);
 int ucs_do_scsi_unmap(struct ufs_dev *dev, struct scsi_unmap_req *req);
@@ -177,4 +176,5 @@
 
 /* This function parses the first byte of the sense data and returns the sense key */
 int parse_sense_key(uint32_t sense_data);
+int ucs_do_request_sense(struct ufs_dev *dev, uint8_t lun);
 #endif
diff --git a/platform/msm_shared/include/ufs.h b/platform/msm_shared/include/ufs.h
index c28c949..0af2dc5 100644
--- a/platform/msm_shared/include/ufs.h
+++ b/platform/msm_shared/include/ufs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* 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
@@ -124,4 +124,5 @@
 uint32_t ufs_get_erase_blk_size(struct ufs_dev* dev);
 void ufs_dump_is_register(struct ufs_dev* dev);
 void ufs_dump_hc_registers(struct ufs_dev* dev);
+void ufs_rpmb_init(struct ufs_dev *dev);
 #endif
diff --git a/platform/msm_shared/mdp5.c b/platform/msm_shared/mdp5.c
index ddda7ee..9978e3a 100755
--- a/platform/msm_shared/mdp5.c
+++ b/platform/msm_shared/mdp5.c
@@ -40,8 +40,7 @@
 #include <clock.h>
 #include <scm.h>
 
-#define MDP_MIN_FETCH		9
-#define MDSS_MDP_MAX_FETCH	12
+#define MDSS_MDP_MAX_PREFILL_FETCH	25
 
 int restore_secure_cfg(uint32_t id);
 
@@ -538,7 +537,8 @@
 					uint32_t intf_base)
 {
 	uint32_t mdp_hw_rev = readl(MDP_HW_REV);
-	uint32_t v_total, h_total, fetch_start, vfp_start, fetch_lines;
+	uint32_t v_total, h_total, fetch_start, vfp_start;
+	uint32_t prefetch_avail, prefetch_needed;
 	uint32_t adjust_xres = 0;
 	uint32_t fetch_enable = BIT(31);
 
@@ -554,10 +554,11 @@
 	/*
 	 * MDP programmable fetch is for MDP with rev >= 1.05.
 	 * Programmable fetch is not needed if vertical back porch
-	 * is >= 9.
+	 * plus vertical puls width is >= 25.
 	 */
 	if (mdp_hw_rev < MDSS_MDP_HW_REV_105 ||
-			lcdc->v_back_porch >= MDP_MIN_FETCH)
+			(lcdc->v_back_porch + lcdc->v_pulse_width) >=
+			MDSS_MDP_MAX_PREFILL_FETCH)
 		return;
 
 	adjust_xres = pinfo->xres;
@@ -574,16 +575,19 @@
 							lcdc->h_front_porch;
 	vfp_start = lcdc->v_pulse_width + lcdc->v_back_porch + pinfo->yres;
 
-	fetch_lines = v_total - vfp_start;
+	prefetch_avail = v_total - vfp_start;
+	prefetch_needed = MDSS_MDP_MAX_PREFILL_FETCH -
+		lcdc->v_back_porch -
+		lcdc->v_pulse_width;
 
 	/*
 	 * In some cases, vertical front porch is too high. In such cases limit
-	 * the mdp fetch lines  as the last 12 lines of vertical front porch.
+	 * the mdp fetch lines  as the last (25 - vbp - vpw) lines of vertical front porch.
 	 */
-	if (fetch_lines > MDSS_MDP_MAX_FETCH)
-		fetch_lines = MDSS_MDP_MAX_FETCH;
+	if (prefetch_avail > prefetch_needed)
+		prefetch_avail = prefetch_needed;
 
-	fetch_start = (v_total - fetch_lines) * h_total + 1;
+	fetch_start = (v_total - prefetch_avail) * h_total + 1;
 
 	if (pinfo->dfps.panel_dfps.enabled)
 		fetch_enable |= BIT(23);
diff --git a/platform/msm_shared/qseecom_lk.c b/platform/msm_shared/qseecom_lk.c
new file mode 100644
index 0000000..4374601
--- /dev/null
+++ b/platform/msm_shared/qseecom_lk.c
@@ -0,0 +1,1400 @@
+/* Copyright (c) 2012-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.
+ */
+
+#define pr_fmt(fmt) "QSEECOM: %s: " fmt, __func__
+
+#include <partition_parser.h>
+#include <qseecom_lk.h>
+#include <scm.h>
+#include <qseecomi_lk.h>
+#include "qseecom_lk_api.h"
+#include <debug.h>
+#include <kernel/mutex.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <arch/defines.h>
+#include <string.h>
+#include <platform/iomap.h>
+#include <platform.h>
+
+#define QSEOS_VERSION_14  0x14
+#define QSEEE_VERSION_00  0x400000
+#define QSEE_VERSION_20   0x800000
+
+
+#define QSEOS_CHECK_VERSION_CMD  0x00001803
+
+#define MAX_SCM_ARGS 10
+#define N_EXT_SCM_ARGS 7
+#define FIRST_EXT_ARG_IDX 3
+
+#define N_REGISTER_ARGS (MAX_SCM_ARGS - N_EXT_SCM_ARGS + 1)
+
+#define QSEE_LOG_BUF_SIZE (4096)
+#define GENERIC_ERROR -1
+#define LISTENER_ALREADY_PRESENT_ERROR -2
+
+#define TZ_CALL 6
+enum qseecom_client_handle_type {
+	QSEECOM_CLIENT_APP = 1,
+	QSEECOM_LISTENER_SERVICE,
+	QSEECOM_SECURE_SERVICE,
+	QSEECOM_GENERIC,
+	QSEECOM_UNAVAILABLE_CLIENT_APP,
+};
+
+struct qseecom_registered_listener_list {
+	struct list_node node;
+	struct qseecom_register_listener_req svc;
+	ListenerCallback CallbackFn;
+};
+
+struct qseecom_registered_app_list {
+	struct list_node node;
+	uint32_t  app_id;
+	uint32_t  ref_cnt;
+	char app_name[MAX_APP_NAME_SIZE];
+	int  handle;
+};
+
+struct qseecom_control {
+	struct list_node  registered_listener_list_head;
+	mutex_t           registered_listener_list_lock;
+
+	struct list_node  registered_app_list_head;
+	mutex_t           registered_app_list_lock;
+
+	uint32_t          qseos_version;
+	uint32_t          qsee_version;
+	int               handle;
+	bool              commonlib_loaded;
+	mutex_t           global_data_lock;
+	uint32_t          cmnlib_loaded;
+	uint32_t          qseecom_init_done;
+	uint32_t          qseecom_tz_init_done;
+};
+
+struct qseecom_listener_handle {
+	uint32_t               id;
+};
+
+static struct qseecom_reg_log_buf_ireq logbuf_req;
+static struct qseecom_control qseecom;
+static int __qseecom_process_incomplete_cmd(struct qseecom_command_scm_resp *resp,
+          struct qseecom_client_listener_data_irsp *send_data_rsp);
+
+/*
+ * Appsbl runs in Aarch32 when this is ported for Aarch64,
+ * change return type for uint64_t.
+ */
+static uint32_t __qseecom_uvirt_to_kphys(uint64_t virt)
+{
+	dprintf(SPEW, "%s called\n", __func__);
+	return (uint32_t)platform_get_virt_to_phys_mapping((addr_t)virt);
+}
+
+static int _disp_log_stats(struct tzdbg_log_t *log, uint32_t log_len,
+		uint32_t startOffset, uint32_t endOffset)
+{
+	uint32_t MaxBufSize = 0;
+	uint32_t LogBufSize = 0;
+	uint32_t LogBufFirstHalf = 0;
+	uint32_t len = 0;
+	char *pCurPos, *pPrintPos = NULL;
+	void *pLogBuf = NULL;
+	int ret = GENERIC_ERROR;
+
+	MaxBufSize = QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_t);
+
+	dprintf(SPEW, "%s called\n", __func__);
+	if (startOffset < endOffset)
+	{
+		LogBufSize = endOffset - startOffset;
+		pLogBuf = malloc(LogBufSize);
+		if (NULL == pLogBuf)
+		{
+			ret = GENERIC_ERROR;
+			dprintf(CRITICAL, "Failed to alloc buffer to print TZ Log:%u\n", LogBufSize);
+			goto err;
+		}
+		memset(pLogBuf, 0, LogBufSize);
+		memscpy(pLogBuf, LogBufSize, (char *)((uint32_t)log->log_buf + startOffset), LogBufSize);
+	}
+	else if ( endOffset < startOffset)
+	{
+		LogBufSize =  MaxBufSize - (startOffset - endOffset);
+		LogBufFirstHalf = MaxBufSize - startOffset;
+		pLogBuf = malloc(LogBufSize);
+		if (NULL == pLogBuf)
+		{
+			ret = GENERIC_ERROR;
+			dprintf(CRITICAL, "Failed to alloc buffer to print TZ Log:%u\n", LogBufSize);
+			goto err;
+		}
+		memset(pLogBuf, 0, LogBufSize);
+		memscpy(pLogBuf, LogBufSize, (char *)((uint32_t)log->log_buf + startOffset), LogBufFirstHalf);
+		memscpy((char *)((uint32_t)pLogBuf+ LogBufFirstHalf), (LogBufSize - LogBufFirstHalf), log->log_buf, endOffset);
+	}
+	else //endOffset == startOffset
+	{
+		ret = 0;
+		goto err;
+	}
+
+	/*
+	 *  Read from ring buff while there is data and space in return buff
+	 */
+	pCurPos = pLogBuf;
+	pPrintPos = pCurPos;
+	while (len < LogBufSize)
+	{
+			//QSEE separate each line by "\r \n"
+			if ((*pCurPos == '\r')&&(*(pCurPos+1) == '\n'))
+			{
+				//update the line to dump
+				*pCurPos = '\0';
+				len++;
+				pCurPos++;
+				*pCurPos = '\0';
+				len++;
+				pCurPos++;
+				dprintf(ALWAYS, "%s\n", pPrintPos);
+				pPrintPos = pCurPos;
+				continue;
+			}
+			len++;
+			pCurPos++;
+	}
+	ret = 0;
+	free(pLogBuf);
+err:
+	return ret;
+}
+
+static int allocate_extra_arg_buffer(uint32_t fn_id, struct scm_desc *desc)
+{
+	int i;
+	int ret = GENERIC_ERROR;
+	scmcall_arg arg = {0};
+	scmcall_ret ret_arg = {0};
+	int arglen = 0;
+
+	if (!desc) {
+		dprintf(CRITICAL, "%s: Invalid input\n", __func__);
+		return GENERIC_ERROR;
+	}
+
+	dprintf(SPEW, "%s called\n", __func__);
+	arglen = desc->arginfo & 0xf;
+
+	dprintf(SPEW, "%s:fn_id:%u, desc->arginfo:%u desc->args[0]:%u desc->args[1]:%u desc->args[2]:%u desc->args[3]:%u desc->args[4]:%u\n",
+			__func__, fn_id, desc->arginfo, desc->args[0], desc->args[1], desc->args[2], desc->args[3], desc->args[4]);
+
+	arg.x0 = fn_id;
+	arg.x1 = desc->arginfo;
+	arg.x2 = desc->args[0];
+	arg.x3 = desc->args[1];
+	arg.x4 = desc->args[2];
+
+	if (arglen > FIRST_EXT_ARG_IDX) {
+		for (i = 0; i < (arglen - FIRST_EXT_ARG_IDX); i++) {
+			arg.x5[i] = desc->args[i + FIRST_EXT_ARG_IDX];
+		}
+	}
+	ret = scm_call2(&arg, &ret_arg);
+	desc->ret[0] = ret_arg.x1;
+	desc->ret[1] = ret_arg.x2;
+	desc->ret[2] = ret_arg.x3;
+
+	dprintf(SPEW, "%s:ret:%d, desc->ret[0]]:%u desc->ret[1]:%u desc->ret[2]:%u\n",
+			__func__, ret, desc->ret[0], desc->ret[1], desc->ret[2]);
+	return ret;
+}
+
+static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
+			const void *req_buf, void *resp_buf)
+{
+	int      ret = 0;
+	uint32_t smc_id = 0;
+	uint32_t qseos_cmd_id = 0;
+	struct scm_desc desc = {0};
+	struct qseecom_command_scm_resp *scm_resp = NULL;
+
+	if (!req_buf || !resp_buf) {
+		dprintf(CRITICAL, "Invalid buffer pointer\n");
+		return GENERIC_ERROR;
+	}
+	dprintf(SPEW, "%s called\n", __func__);
+
+	qseos_cmd_id = *(uint32_t *)req_buf;
+	scm_resp = (struct qseecom_command_scm_resp *)resp_buf;
+
+	switch (svc_id) {
+		case TZ_CALL: {
+			if (tz_cmd_id == 1) {
+				smc_id = TZ_INFO_IS_SVC_AVAILABLE_ID;
+				desc.arginfo = TZ_INFO_IS_SVC_AVAILABLE_ID_PARAM_ID;
+				desc.args[0] = TZ_INFO_GET_FEATURE_VERSION_ID;
+			} else if (tz_cmd_id == 3) {
+				smc_id = TZ_INFO_GET_FEATURE_VERSION_ID;
+				desc.arginfo = TZ_INFO_GET_FEATURE_VERSION_ID_PARAM_ID;
+				desc.args[0] = *(uint32_t *)req_buf;
+			}
+			ret = allocate_extra_arg_buffer(smc_id, &desc);
+			break;
+		}
+
+		case SCM_SVC_TZSCHEDULER: {
+			switch (qseos_cmd_id) {
+				case QSEE_APP_START_COMMAND: {
+					struct qseecom_load_app_ireq *req;
+					req = (struct qseecom_load_app_ireq *)req_buf;
+					smc_id = TZ_OS_APP_START_ID;
+					desc.arginfo = TZ_OS_APP_START_ID_PARAM_ID;
+					desc.args[0] = req->mdt_len;
+					desc.args[1] = req->img_len;
+					desc.args[2] = req->phy_addr;
+					dprintf(SPEW, "args[0]:%u args[1]:%u args[2]:%u\n",
+							desc.args[0], desc.args[1], desc.args[2]);
+					dprintf(SPEW, "mdt_len:%u img_len:%u phy_addr:%u\n",
+							req->mdt_len, req->img_len, req->phy_addr);
+					ret = allocate_extra_arg_buffer(smc_id, &desc);
+
+					break;
+				}
+				case QSEE_APP_SHUTDOWN_COMMAND: {
+					struct qseecom_unload_app_ireq *req;
+					req = (struct qseecom_unload_app_ireq *)req_buf;
+					smc_id = TZ_OS_APP_SHUTDOWN_ID;
+					desc.arginfo = TZ_OS_APP_SHUTDOWN_ID_PARAM_ID;
+					desc.args[0] = req->app_id;
+					ret = allocate_extra_arg_buffer(smc_id, &desc);
+					break;
+				}
+				case QSEE_APP_REGION_NOTIFICATION: {
+					struct qsee_apps_region_info_ireq *req;
+					req = (struct qsee_apps_region_info_ireq *)req_buf;
+					smc_id = TZ_OS_APP_REGION_NOTIFICATION_ID;
+					desc.arginfo =
+						TZ_OS_APP_REGION_NOTIFICATION_ID_PARAM_ID;
+					desc.args[0] = req->addr;
+					desc.args[1] = req->size;
+					ret = allocate_extra_arg_buffer(smc_id, &desc);
+					break;
+				}
+				case QSEE_LOAD_SERV_IMAGE_COMMAND: {
+					struct qseecom_load_app_ireq *req;
+					req = (struct qseecom_load_app_ireq *)req_buf;
+					smc_id = TZ_OS_LOAD_SERVICES_IMAGE_ID;
+					desc.arginfo = TZ_OS_LOAD_SERVICES_IMAGE_ID_PARAM_ID;
+					desc.args[0] = req->mdt_len;
+					desc.args[1] = req->img_len;
+					desc.args[2] = req->phy_addr;
+					dprintf(SPEW, "QSEE_LOAD_SERV_IMAGE_COMMAND mdt_len:%u img_len:%u phy_addr:%u\n",
+							req->mdt_len, req->img_len, req->phy_addr);
+					ret = allocate_extra_arg_buffer(smc_id, &desc);
+					break;
+				}
+				case QSEE_UNLOAD_SERV_IMAGE_COMMAND: {
+					smc_id = TZ_OS_UNLOAD_SERVICES_IMAGE_ID;
+					desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID;
+					ret = allocate_extra_arg_buffer(smc_id, &desc);
+					break;
+				}
+				case QSEE_REGISTER_LISTENER: {
+					struct qseecom_register_listener_ireq *req;
+					req = (struct qseecom_register_listener_ireq *)req_buf;
+					smc_id = TZ_OS_REGISTER_LISTENER_ID;
+					desc.arginfo =
+						TZ_OS_REGISTER_LISTENER_ID_PARAM_ID;
+					desc.args[0] = req->listener_id;
+					desc.args[1] = req->sb_ptr;
+					desc.args[2] = req->sb_len;
+					ret = allocate_extra_arg_buffer(smc_id, &desc);
+					break;
+				}
+				case QSEE_DEREGISTER_LISTENER: {
+					struct qseecom_unregister_listener_ireq *req;
+					req = (struct qseecom_unregister_listener_ireq *)
+						req_buf;
+					smc_id = TZ_OS_DEREGISTER_LISTENER_ID;
+					desc.arginfo = TZ_OS_DEREGISTER_LISTENER_ID_PARAM_ID;
+					desc.args[0] = req->listener_id;
+					ret = allocate_extra_arg_buffer(smc_id, &desc);
+					break;
+				}
+				case QSEE_LISTENER_DATA_RSP_COMMAND: {
+					struct qseecom_client_listener_data_irsp *req;
+					req = (struct qseecom_client_listener_data_irsp *)
+						req_buf;
+					smc_id = TZ_OS_LISTENER_RESPONSE_HANDLER_ID;
+					desc.arginfo =
+						TZ_OS_LISTENER_RESPONSE_HANDLER_ID_PARAM_ID;
+					desc.args[0] = req->listener_id;
+					desc.args[1] = req->status;
+					ret = allocate_extra_arg_buffer(smc_id, &desc);
+					break;
+				}
+				case QSEE_CLIENT_SEND_DATA_COMMAND: {
+					struct qseecom_client_send_data_ireq *req;
+					req = (struct qseecom_client_send_data_ireq *)req_buf;
+					smc_id = TZ_APP_QSAPP_SEND_DATA_ID;
+					desc.arginfo = TZ_APP_QSAPP_SEND_DATA_ID_PARAM_ID;
+					desc.args[0] = req->app_id;
+					desc.args[1] = req->req_ptr;
+					desc.args[2] = req->req_len;
+					desc.args[3] = req->rsp_ptr;
+					desc.args[4] = req->rsp_len;
+					ret = allocate_extra_arg_buffer(smc_id, &desc);
+					break;
+				}
+				case QSEE_RPMB_PROVISION_KEY_COMMAND: {
+					struct qseecom_client_send_service_ireq *req;
+					req = (struct qseecom_client_send_service_ireq *)
+						req_buf;
+					smc_id = TZ_OS_RPMB_PROVISION_KEY_ID;
+					desc.arginfo = TZ_OS_RPMB_PROVISION_KEY_ID_PARAM_ID;
+					desc.args[0] = req->key_type;
+					ret = allocate_extra_arg_buffer(smc_id, &desc);
+					break;
+				}
+				case QSEE_RPMB_ERASE_COMMAND: {
+					smc_id = TZ_OS_RPMB_ERASE_ID;
+					desc.arginfo = TZ_OS_RPMB_ERASE_ID_PARAM_ID;
+					ret = allocate_extra_arg_buffer(smc_id, &desc);
+					break;
+				}
+
+				case QSEE_REGISTER_LOG_BUF_COMMAND: {
+					struct qseecom_reg_log_buf_ireq *req;
+					req = (struct qseecom_reg_log_buf_ireq *)req_buf;
+					smc_id = TZ_OS_REGISTER_LOG_BUFFER_ID;
+					desc.arginfo = TZ_OS_REGISTER_LOG_BUFFER_ID_PARAM_ID;
+					desc.args[0] = req->phy_addr;
+					desc.args[1] = req->len;
+					ret = allocate_extra_arg_buffer(smc_id, &desc);
+					break;
+				}
+				default: {
+					dprintf(CRITICAL, "qseos_cmd_id 0x%d is not supported by armv8 scm_call2.\n",
+								qseos_cmd_id);
+					ret = GENERIC_ERROR;
+					break;
+				}
+			} /*end of switch (qsee_cmd_id)  */
+			break;
+		} /*end of case SCM_SVC_TZSCHEDULER*/
+		default: {
+			dprintf(CRITICAL, "svc_id 0x%x is not supported by armv8 scm_call2.\n",
+						svc_id);
+			ret = GENERIC_ERROR;
+			break;
+		}
+	} /*end of switch svc_id */
+	scm_resp->result = desc.ret[0];
+	scm_resp->resp_type = desc.ret[1];
+	scm_resp->data = desc.ret[2];
+	dprintf(SPEW, "svc_id = 0x%x, tz_cmd_id = 0x%x, qseos_cmd_id = 0x%x, smc_id = 0x%x, param_id = 0x%x\n",
+		svc_id, tz_cmd_id, qseos_cmd_id, smc_id, desc.arginfo);
+	dprintf(SPEW, "scm_resp->result = 0x%x, scm_resp->resp_type = 0x%x, scm_resp->data = 0x%x\n",
+		scm_resp->result, scm_resp->resp_type, scm_resp->data);
+	return ret;
+}
+
+static int qseecom_scm_call(uint32_t svc_id, uint32_t tz_cmd_id, void *cmd_buf,
+		size_t cmd_len, void *resp_buf, size_t resp_len)
+{
+	void *req = NULL;
+	struct qseecom_command_scm_resp *resp = NULL;
+	struct qseecom_client_listener_data_irsp send_data_rsp = {0};
+	int ret = GENERIC_ERROR;
+	uint32_t qseos_cmd_id = 0;
+
+	if ((!cmd_buf) || (!resp_buf))
+			return GENERIC_ERROR;
+
+	dprintf(SPEW, "%s called\n", __func__);
+	mutex_acquire(&qseecom.registered_app_list_lock);
+	req = cmd_buf;
+	qseos_cmd_id = *(uint32_t *)req;
+	resp = (struct qseecom_command_scm_resp *) resp_buf;
+
+	do {
+		if (!is_scm_armv8_support()) {
+			ret = scm_call(svc_id, tz_cmd_id, req, cmd_len,
+					resp_buf, resp_len);
+		} else {
+			ret = qseecom_scm_call2(svc_id, tz_cmd_id, req, resp);
+		}
+
+		if (ret) {
+			dprintf(CRITICAL, "ERROR: scm_call to load failed : ret %d\n", ret);
+			ret = GENERIC_ERROR;
+			goto err;
+		}
+
+		if (svc_id == TZ_CALL) {
+			goto err;
+		}
+
+		switch (resp->result) {
+			case QSEOS_RESULT_SUCCESS:
+				if(((resp->resp_type != QSEOS_APP_ID) || (resp->data <= 0)) &&
+					((qseos_cmd_id == QSEE_CLIENT_SEND_DATA_COMMAND) ||
+							(qseos_cmd_id == QSEE_LISTENER_DATA_RSP_COMMAND)))
+				{
+					dprintf(CRITICAL, "ERROR: Resp type %d or Resp Data %d incorrect\n",
+							resp->resp_type, resp->data);
+					ret = GENERIC_ERROR;
+					goto err;
+				}
+				goto err;
+			case QSEOS_RESULT_FAILURE:
+				dprintf(CRITICAL, "scm call failed w/response result%d\n", resp->result);
+				ret = GENERIC_ERROR;
+				goto err;
+			case  QSEOS_RESULT_INCOMPLETE:
+				if(resp->resp_type != QSEOS_LISTENER_ID)
+				{
+					ret = GENERIC_ERROR;
+					dprintf(CRITICAL, "Listener service incorrect resp->result:%d resp->resp_type:%d\n",
+							resp->result, resp->resp_type);
+					goto err;
+				}
+				__qseecom_process_incomplete_cmd(resp, &send_data_rsp);
+				req = (void *)&send_data_rsp;
+				qseos_cmd_id = QSEE_LISTENER_DATA_RSP_COMMAND;
+				break;
+			default:
+				dprintf(CRITICAL, "scm call return unknown response %d\n",	resp->result);
+				ret = GENERIC_ERROR;
+				goto err;
+		}
+	} while(true);
+
+err:
+	mutex_release(&qseecom.registered_app_list_lock);
+	return ret;
+
+}
+
+static int __qseecom_process_incomplete_cmd(struct qseecom_command_scm_resp *resp,
+		struct qseecom_client_listener_data_irsp *send_data_rsp)
+{
+	int ret = 0;
+	struct qseecom_registered_listener_list *entry;
+
+	if ((!resp) || (!send_data_rsp))
+	{
+		return GENERIC_ERROR;
+	}
+
+	dprintf(SPEW, "%s called\n", __func__);
+	mutex_acquire(&qseecom.global_data_lock);
+
+	list_for_every_entry(&qseecom.registered_listener_list_head,
+			entry, struct qseecom_registered_listener_list, node) {
+		if (resp->data == entry->svc.listener_id) {
+			arch_invalidate_cache_range((addr_t) entry->svc.virt_sb_base, entry->svc.sb_size);
+			entry->CallbackFn(entry->svc.virt_sb_base, entry->svc.sb_size);
+			arch_clean_invalidate_cache_range((addr_t) entry->svc.virt_sb_base, entry->svc.sb_size);
+			break;
+		}
+	}
+	send_data_rsp->qsee_cmd_id = QSEE_LISTENER_DATA_RSP_COMMAND;
+	send_data_rsp->listener_id  = entry->svc.listener_id;
+	send_data_rsp->status  = 0;
+	mutex_release(&qseecom.global_data_lock);
+	return ret;
+}
+
+static int __qseecom_load_app(const char *app_name, unsigned int *app_id)
+{
+	int index = INVALID_PTN;
+	unsigned long long ptn = 0;
+	unsigned long long size = 0;
+	void *buf = NULL;
+	void *req = NULL;
+	struct qseecom_load_app_ireq load_req = {0};
+	struct qseecom_command_scm_resp resp;
+	struct tzdbg_log_t *log = NULL;
+	uint32_t QseeLogStart = 0;
+	uint32_t QseeLogNewStart = 0;
+
+	int ret = GENERIC_ERROR;
+	uint8_t lun = 0;
+
+	if (!app_name)
+		return GENERIC_ERROR;
+
+	dprintf(SPEW, "%s called\n", __func__);
+	index = partition_get_index(app_name);
+	lun = partition_get_lun(index);
+	mmc_set_lun(lun);
+
+	size = partition_get_size(index);
+
+	buf = memalign(PAGE_SIZE, ROUNDUP(size, PAGE_SIZE));
+	if (!buf) {
+		dprintf(CRITICAL, "%s: Aloc failed for %s image\n",
+				__func__, app_name);
+		ret = GENERIC_ERROR;
+		goto err;
+	}
+
+	ptn = partition_get_offset(index);
+	if(ptn == 0) {
+		dprintf(CRITICAL, "ERROR: No %s found\n", app_name);
+		ret = GENERIC_ERROR;
+		goto err;
+	}
+	if (mmc_read(ptn, (unsigned int *) buf, size)) {
+		dprintf(CRITICAL, "ERROR: Cannot read %s image\n", app_name);
+		ret = GENERIC_ERROR;
+		goto err;
+	}
+
+	/* Currently on 8994 only 32-bit phy addr is supported
+	 * Hence downcasting is okay
+	 */
+	load_req.phy_addr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
+	load_req.qsee_cmd_id = QSEE_APP_START_COMMAND;
+	load_req.img_len = size;
+	load_req.mdt_len = 0;
+	dprintf(SPEW, "phy_addr:%u img_len:%u\n", load_req.phy_addr, load_req.img_len);
+
+	memscpy(&load_req.app_name, MAX_APP_NAME_SIZE, app_name, MAX_APP_NAME_SIZE);
+	req = (void *)&load_req;
+
+	log = (struct tzdbg_log_t *)logbuf_req.phy_addr;
+	arch_invalidate_cache_range((addr_t) logbuf_req.phy_addr, logbuf_req.len);
+	QseeLogStart = (uint32_t) log->log_pos.offset;
+
+	arch_clean_invalidate_cache_range((addr_t) load_req.phy_addr, load_req.img_len);
+	ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, req,
+				sizeof(struct qseecom_load_lib_image_ireq),
+							&resp, sizeof(resp));
+	if(ret == 0)
+		*app_id = resp.data;
+	else
+		*app_id = 0;
+	arch_invalidate_cache_range((addr_t) logbuf_req.phy_addr, logbuf_req.len);
+	QseeLogNewStart = (uint32_t) log->log_pos.offset;
+
+	_disp_log_stats((struct tzdbg_log_t *) logbuf_req.phy_addr, QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_t),
+			QseeLogStart, QseeLogNewStart);
+err:
+	if (buf)
+		free(buf);
+	return ret;
+}
+
+static int qseecom_load_commonlib_image(char * app_name)
+{
+	int index = INVALID_PTN;
+	unsigned long long ptn = 0;
+	unsigned long long size = 0;
+	void *buf = NULL;
+	void *req = NULL;
+	struct qseecom_load_app_ireq load_req = {0};
+	struct qseecom_command_scm_resp resp = {0};
+	int ret = GENERIC_ERROR;
+	uint8_t lun = 0;
+
+	dprintf(SPEW, "%s called\n", __func__);
+	index = partition_get_index(app_name);
+	lun = partition_get_lun(index);
+	mmc_set_lun(lun);
+
+	size = partition_get_size(index);
+
+	buf = memalign(PAGE_SIZE, ROUNDUP(size, PAGE_SIZE));
+	if (!buf) {
+		dprintf(CRITICAL, "%s: Aloc failed for %s image\n",
+				__func__, app_name);
+		ret = GENERIC_ERROR;
+		goto err;
+	}
+
+	ptn = partition_get_offset(index);
+	if(ptn == 0) {
+		dprintf(CRITICAL, "ERROR: No %s found\n", app_name);
+		ret = GENERIC_ERROR;
+		goto err;
+	}
+	if (mmc_read(ptn, (unsigned int *) buf, size)) {
+		dprintf(CRITICAL, "ERROR: Cannot read %s image\n", app_name);
+		ret = GENERIC_ERROR;
+		goto err;
+	}
+
+	/* Currently on 8994 only 32-bit phy addr is supported
+	 * Hence downcasting is okay
+	 */
+	load_req.phy_addr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
+	load_req.qsee_cmd_id = QSEE_LOAD_SERV_IMAGE_COMMAND;
+	load_req.img_len = size;
+	load_req.mdt_len = 0;
+
+	memscpy(load_req.app_name, MAX_APP_NAME_SIZE, app_name, MAX_APP_NAME_SIZE);
+	req = (void *)&load_req;
+
+	arch_clean_invalidate_cache_range((addr_t) load_req.phy_addr, load_req.img_len);
+	ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, req,
+				sizeof(struct qseecom_load_lib_image_ireq),
+							&resp, sizeof(resp));
+	if(ret == 0)
+		ret = resp.data;
+
+err:
+	if (buf)
+		free(buf);
+	return ret;
+}
+
+static int qseecom_unload_commonlib_image(void)
+{
+	int ret = GENERIC_ERROR;
+	struct qseecom_unload_lib_image_ireq unload_req = {0};
+	struct qseecom_command_scm_resp resp;
+
+	dprintf(SPEW, "%s called\n", __func__);
+	/* Populate the remaining parameters */
+	unload_req.qsee_cmd_id = QSEE_UNLOAD_SERV_IMAGE_COMMAND;
+	/* SCM_CALL to load the image */
+	ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &unload_req,
+			sizeof(struct qseecom_unload_lib_image_ireq),
+						&resp, sizeof(resp));
+	return ret;
+}
+
+/*
+ * This function is called with the global
+ * data mutex acquired.
+ */
+static struct qseecom_registered_app_list *
+	__qseecom_add_app_entry(char *app_name, uint32_t app_id)
+{
+	struct qseecom_registered_app_list *entry = NULL;
+	int32_t ret = GENERIC_ERROR;
+
+	if ((!app_name) || (app_id == 0)) {
+		dprintf(CRITICAL, "%s: Invalid Input\n", __func__);
+		return NULL;
+	}
+	dprintf(SPEW, "%s called\n", __func__);
+
+	entry = malloc(sizeof(*entry));
+	if (!entry) {
+		dprintf(CRITICAL, "malloc for app entry failed\n");
+		ret =  GENERIC_ERROR;
+		goto err;
+	}
+	entry->app_id = app_id;
+	entry->ref_cnt = 1;
+	strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE);
+
+	dprintf(SPEW, "%s: Adding app:%s app_id:%u to list\n", __func__, entry->app_name, entry->app_id);
+	list_add_tail(&qseecom.registered_app_list_head, &entry->node);
+	ret = 0;
+err:
+	if (entry && (ret < 0)) {
+		free(entry);
+		return NULL;
+	}
+	return entry;
+}
+
+/*
+ * This function is called with the global
+ * data mutex acquired.
+ */
+static int
+	__qseecom_remove_app_entry(struct qseecom_registered_app_list *entry)
+{
+	if (!entry) {
+		dprintf(CRITICAL, "%s: Invalid Input\n", __func__);
+		return GENERIC_ERROR;
+	}
+	dprintf(SPEW, "%s called\n", __func__);
+	list_delete(&entry->node);
+	free(entry);
+
+	return 0;
+}
+
+/*
+ * This function is called with the global
+ * data mutex acquired.
+ */
+struct qseecom_registered_listener_list *
+	__qseecom_check_listener_exists(uint32_t listener_id)
+{
+	struct qseecom_registered_listener_list *entry = NULL;
+	bool listener_present = false;
+
+	if (!listener_id) {
+		dprintf(CRITICAL, "%s: Invalid Input\n", __func__);
+		return NULL;
+	}
+	dprintf(SPEW, "%s called\n", __func__);
+
+	list_for_every_entry(&qseecom.registered_listener_list_head,
+			entry, struct qseecom_registered_listener_list, node) {
+		if (entry->svc.listener_id == listener_id) {
+			listener_present = true;
+			break;
+		}
+	}
+	if (listener_present)
+		return entry;
+	else
+		return NULL;
+}
+
+/*
+ * This function is called with the global
+ * data mutex acquired.
+ */
+static struct qseecom_registered_app_list
+	*__qseecom_check_handle_exists(int handle)
+{
+	struct qseecom_registered_app_list *entry;
+	bool app_present = false;
+
+	if (handle <= 0) {
+		dprintf(CRITICAL, "%s: Invalid Input\n", __func__);
+		return NULL;
+	}
+	dprintf(SPEW, "%s called\n", __func__);
+	list_for_every_entry(&qseecom.registered_app_list_head,
+			entry, struct qseecom_registered_app_list, node) {
+		if (entry->handle == handle) {
+			app_present = true;
+			break;
+		}
+	}
+
+	if (app_present == true)
+		return entry;
+	else
+		return NULL;
+
+}
+
+
+static struct qseecom_registered_app_list *
+	__qseecom_check_app_exists(char *app_name)
+{
+	struct qseecom_registered_app_list *entry = NULL;
+
+	dprintf(SPEW, "%s called\n", __func__);
+	list_for_every_entry(&qseecom.registered_app_list_head,
+			entry, struct qseecom_registered_app_list, node) {
+		if (!strncmp(app_name, entry->app_name, 32)) {
+			dprintf(SPEW, "%s: app_name:%s\n", __func__, app_name);
+			return entry;
+		}
+	}
+	return NULL;
+}
+
+static int qseecom_unload_app(uint32_t app_id)
+{
+	int ret = 0;
+	struct qseecom_command_scm_resp resp;
+	struct qseecom_unload_app_ireq req;
+
+	dprintf(SPEW, "%s called\n", __func__);
+	/* Populate the structure for sending scm call to load image */
+	req.qsee_cmd_id = QSEE_APP_SHUTDOWN_COMMAND;
+	req.app_id = app_id;
+
+	/* SCM_CALL to unload the app */
+	ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
+			sizeof(struct qseecom_unload_app_ireq),
+			&resp, sizeof(resp));
+
+	return ret;
+}
+
+
+static int __qseecom_send_cmd(uint32_t app_id, struct qseecom_send_cmd_req *req)
+{
+	int ret = 0;
+	struct qseecom_client_send_data_ireq send_data_req;
+	struct qseecom_command_scm_resp resp;
+	void *buf = NULL;
+	uint32_t size = 0;
+
+	if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
+		dprintf(CRITICAL, "%s: cmd buffer or response buffer is null\n",
+				__func__);
+		return GENERIC_ERROR;
+	}
+	dprintf(SPEW, "%s called\n", __func__);
+
+	/* Allocate for req or rsp len whichever is higher, both req and rsp point
+	 * to the same buffer
+	 */
+	size = (req->cmd_req_len > req->resp_len) ? req->cmd_req_len : req->resp_len;
+
+	/* The req rsp buffer will be xPU protected by TZ during a TZ APP call
+	 * This will still be protected during a listener call and there is a
+	 * possibility of prefetching happening, which will cause xPU violation.
+	 * Hence using (device memory with xN set) to prevent I or D prefetching.
+	 * This is a contiguous region of 1MB used only for this, hence will not
+	 * free this.
+	 */
+	buf = (void *)RPMB_SND_RCV_BUF;
+	if (!buf) {
+		dprintf(CRITICAL, "%s: Aloc failed for app_id:%d of size:%d\n",
+				__func__, app_id, size);
+		return GENERIC_ERROR;
+	}
+
+	memscpy(buf, ROUNDUP(size, PAGE_SIZE), req->cmd_req_buf, req->cmd_req_len);
+
+	send_data_req.qsee_cmd_id = QSEE_CLIENT_SEND_DATA_COMMAND;
+	send_data_req.app_id = app_id;
+
+	/* Currently on 8994 only 32-bit phy addr is supported
+	 * Hence downcasting is okay
+	 */
+	send_data_req.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
+	send_data_req.req_len = req->cmd_req_len;
+	send_data_req.rsp_ptr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
+	send_data_req.rsp_len = req->resp_len;
+
+	ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
+				(void *)&send_data_req,
+				sizeof(send_data_req), (void *)&resp, sizeof(resp));
+
+	memscpy(req->resp_buf, req->resp_len, (void *)send_data_req.rsp_ptr, send_data_req.rsp_len);
+	return ret;
+}
+
+/**
+* Start a Secure App
+*
+* @param char* app_name
+*   App name of the Secure App to be started
+*
+* @return int
+*   Success:	handle to be used for all calls to
+*   			Secure app. Always greater than zero.
+*   Failure:	Error code (negative only).
+*/
+int qseecom_start_app(char *app_name)
+{
+	int32_t ret = GENERIC_ERROR;
+	int handle = 0;
+	struct qseecom_registered_app_list *entry = NULL;
+	unsigned int app_id = 0;
+
+	if (!app_name) {
+		dprintf(CRITICAL, "%s: Input error\n", __func__);
+		goto err;
+	}
+	dprintf(SPEW, "%s called\n", __func__);
+
+
+	mutex_acquire(&qseecom.global_data_lock);
+	if ((!qseecom.qseecom_init_done)
+			|| (!qseecom.qseecom_tz_init_done)){
+		dprintf(CRITICAL, "%s qseecom_init not done\n",
+							__func__);
+		mutex_release(&qseecom.global_data_lock);
+		return ret;
+	}
+	/* Load commonlib image*/
+	if (!qseecom.cmnlib_loaded) {
+		ret = qseecom_load_commonlib_image("cmnlib");
+		if (ret) {
+			mutex_release(&qseecom.global_data_lock);
+			dprintf(CRITICAL, "%s qseecom_load_commonlib_image failed with status:%d\n",
+					__func__, ret);
+			goto err;
+		}
+		qseecom.cmnlib_loaded = 1;
+	}
+	/* Check if App already exits, if exits increase ref_cnt
+	 * and return handle, else load the app from partition,
+	 * call into TZ to load it, add to list and then return
+	 * handle.
+	 */
+
+	entry = __qseecom_check_app_exists(app_name);
+	if (!entry) {
+		mutex_release(&qseecom.global_data_lock);
+		/* load the app and get the app_id  */
+		dprintf(INFO, "%s: Loading app %s for the first time'\n",
+				__func__, app_name);
+
+		ret = __qseecom_load_app(app_name, &app_id);
+		if ((ret < 0) || (app_id ==0)) {
+			dprintf(CRITICAL, "%s: __qseecom_load_app failed with err:%d for app:%s\n",
+					__func__, ret, app_name);
+			ret = GENERIC_ERROR;
+			goto err;
+		}
+		mutex_acquire(&qseecom.global_data_lock);
+		entry = __qseecom_add_app_entry(app_name, app_id);
+		if (!entry)
+		{
+			dprintf(CRITICAL, "%s: __qseecom_add_app_entry failed\n", __func__);
+			ret = GENERIC_ERROR;
+			mutex_release(&qseecom.global_data_lock);
+			goto err;
+		}
+		qseecom.handle++;
+		entry->handle = qseecom.handle;
+		handle = entry->handle;
+		mutex_release(&qseecom.global_data_lock);
+	}
+	else {
+		entry->ref_cnt++;
+		handle = entry->handle;
+		mutex_release(&qseecom.global_data_lock);
+	}
+	return handle;
+err:
+	return ret;
+}
+
+/**
+* Shutdown a Secure App
+*
+* @param int handle
+*   Handle  of the Secure App to be shutdown
+*
+* @return int
+*   Status:
+*     0 - Success
+*     Negative value indicates failure.
+*/
+int qseecom_shutdown_app(int handle)
+{
+	int ret = GENERIC_ERROR;
+	int ref_cnt = 0;
+	struct qseecom_registered_app_list *entry = NULL;
+	struct tzdbg_log_t *log = NULL;
+	uint32_t QseeLogStart = 0;
+	uint32_t QseeLogNewStart = 0;
+
+	if (handle <= 0) {
+		dprintf(CRITICAL, "%s: Invalid Handle %d\n", __func__, handle);
+		goto err;
+	}
+	dprintf(SPEW, "%s called\n", __func__);
+	mutex_acquire(&qseecom.global_data_lock);
+	if ((!qseecom.qseecom_init_done)
+			|| (!qseecom.qseecom_tz_init_done)) {
+		dprintf(CRITICAL, "%s qseecom_init not done\n",
+							__func__);
+		mutex_release(&qseecom.global_data_lock);
+		return ret;
+	}
+	entry = __qseecom_check_handle_exists(handle);
+	if (!entry) {
+		dprintf(CRITICAL, "%s: Shutdown on an app that was never loaded handle:%d\n",
+				__func__, handle);
+		ret = GENERIC_ERROR;
+		mutex_release(&qseecom.global_data_lock);
+		goto err;
+	}
+
+	/* Decrement ref_cnt by 1, if ref_cnt is 0 after
+	 * decrementing unload the app by calling into
+	 * TZ else just return.
+	 */
+
+	if(entry->ref_cnt != 0)
+		entry->ref_cnt--;
+	ref_cnt = entry->ref_cnt;
+	mutex_release(&qseecom.global_data_lock);
+	if (ref_cnt == 0) {
+		log = (struct tzdbg_log_t *)logbuf_req.phy_addr;
+		arch_invalidate_cache_range((addr_t) logbuf_req.phy_addr, logbuf_req.len);
+		QseeLogStart = (uint32_t) log->log_pos.offset;
+
+		ret = qseecom_unload_app(entry->app_id);
+		arch_invalidate_cache_range((addr_t) logbuf_req.phy_addr, logbuf_req.len);
+		QseeLogNewStart = (uint32_t) log->log_pos.offset;
+
+		_disp_log_stats((struct tzdbg_log_t *) logbuf_req.phy_addr, QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_t),
+				QseeLogStart, QseeLogNewStart);
+		if(ret) {
+			dprintf(CRITICAL, "%s: qseecom_unload_app failed with err:%d for handle:%d\n",
+					__func__, ret, handle);
+			goto err;
+		}
+		mutex_acquire(&qseecom.global_data_lock);
+		ret = __qseecom_remove_app_entry(entry);
+		mutex_release(&qseecom.global_data_lock);
+		if(ret) {
+			dprintf(CRITICAL, "%s: __qseecom_remove_app_entry failed with err:%d for handle:%d\n",
+					__func__, ret, handle);
+			goto err;
+		}
+	}
+	ret = 0;
+err:
+	return ret;
+}
+
+/**
+* Send cmd to a Secure App
+*
+* @param int handle
+*   Handle  of the Secure App to send the cmd
+*
+* @param void *send_buf
+*   Pointer to the App request buffer
+*
+* @param uint32_t sbuf_len
+*   Size of the request buffer
+*
+* @param void *resp_buf
+*   Pointer to the App response buffer
+*
+* @param uint32_t rbuf_len
+*   Size of the response buffer
+*
+* @return int
+*   Status:
+*     0 - Success
+*     Negative value indicates failure.
+*/
+int qseecom_send_command(int handle, void *send_buf,
+			uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len)
+{
+	int ret = GENERIC_ERROR;
+	uint32_t app_id = 0;
+	struct qseecom_registered_app_list *entry = NULL;
+	struct qseecom_send_cmd_req req = {0, 0, 0, 0};
+	struct tzdbg_log_t *log = NULL;
+	uint32_t QseeLogStart = 0;
+	uint32_t QseeLogNewStart = 0;
+
+	if (handle <= 0) {
+		dprintf(CRITICAL, "%s Handle is Invalid\n", __func__);
+		return GENERIC_ERROR;
+	}
+
+	if((!send_buf) || (!resp_buf)) {
+		dprintf(CRITICAL, "%s: Input Buffers invalid\n", __func__);
+		return GENERIC_ERROR;
+	}
+	dprintf(SPEW, "%s called\n", __func__);
+	mutex_acquire(&qseecom.global_data_lock);
+	if ((!qseecom.qseecom_init_done)
+			|| (!qseecom.qseecom_tz_init_done)) {
+		dprintf(CRITICAL, "%s qseecom_init not done\n",
+							__func__);
+		mutex_release(&qseecom.global_data_lock);
+		return ret;
+	}
+	entry = __qseecom_check_handle_exists(handle);
+	if (!entry) {
+		dprintf(CRITICAL, "%s: Send cmd on an app that was never loaded handle:%d\n",
+				__func__, handle);
+		ret = GENERIC_ERROR;
+		mutex_release(&qseecom.global_data_lock);
+		goto err;
+	}
+
+	app_id = entry->app_id;
+	mutex_release(&qseecom.global_data_lock);
+
+	req.cmd_req_len = sbuf_len;
+	req.resp_len = rbuf_len;
+	req.cmd_req_buf = send_buf;
+	req.resp_buf = resp_buf;
+
+	log = (struct tzdbg_log_t *)logbuf_req.phy_addr;
+	arch_invalidate_cache_range((addr_t) logbuf_req.phy_addr, logbuf_req.len);
+	QseeLogStart = (uint32_t) log->log_pos.offset;
+
+	ret = __qseecom_send_cmd(app_id, &req);
+	if (ret) {
+		dprintf(CRITICAL, "%s __qseecom_send_cmd failed with err:%d for handle:%d\n",
+				__func__, ret, handle);
+		goto err;
+	}
+	arch_invalidate_cache_range((addr_t) logbuf_req.phy_addr, logbuf_req.len);
+	QseeLogNewStart = (uint32_t) log->log_pos.offset;
+
+	_disp_log_stats((struct tzdbg_log_t *) logbuf_req.phy_addr, QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_t),
+			QseeLogStart, QseeLogNewStart);
+	ret = 0;
+	dprintf(SPEW, "sending cmd_req->rsp size: %u, ptr: 0x%p\n",
+			req.resp_len, req.resp_buf);
+err:
+	return ret;
+}
+
+/**
+* Registers a Listener Service with QSEE
+*
+* @param uint32_t listnr_id
+*   Pre-defined Listener ID to be registered
+*
+* @param uint32_t sb_size
+*   Shared buffer size required for the listener
+*   service.
+*
+* @return int
+*   Status:
+*     0 - Success
+*     Negative value indicates failure.
+*/
+int qseecom_register_listener(struct qseecom_listener_services *listnr)
+{
+	int ret = GENERIC_ERROR;
+	struct qseecom_registered_listener_list *new_entry = NULL;
+	struct qseecom_register_listener_ireq req;
+	struct qseecom_command_scm_resp resp;
+
+	mutex_acquire(&qseecom.global_data_lock);
+	if (!qseecom.qseecom_init_done) {
+		dprintf(CRITICAL, "%s qseecom_init not done\n",
+							__func__);
+		mutex_release(&qseecom.global_data_lock);
+		return ret;
+	}
+	mutex_release(&qseecom.global_data_lock);
+
+	mutex_acquire(&qseecom.registered_listener_list_lock);
+
+	if ((!listnr)) {
+		dprintf(CRITICAL, "%s Invalid Input listnr\n", __func__);
+		return GENERIC_ERROR;
+	}
+
+	if ((!listnr->id) || (!listnr->sb_size) || (!listnr->service_cmd_handler)) {
+		dprintf(CRITICAL, "%s Invalid Input listnr_id:%d sb_size:%d\n",
+				__func__, listnr->id, listnr->sb_size);
+		return GENERIC_ERROR;
+	}
+	dprintf(SPEW, "%s called\n", __func__);
+	new_entry = __qseecom_check_listener_exists(listnr->id);
+	if (new_entry) {
+		dprintf(CRITICAL, "Service is not unique and is already registered\n");
+		ret = LISTENER_ALREADY_PRESENT_ERROR;
+		goto err;
+	}
+
+	new_entry = malloc(sizeof(*new_entry));
+	if (!new_entry) {
+		dprintf(CRITICAL, "%s new_entry malloc failed for size:%d\n", __func__, sizeof(*new_entry));
+		ret = GENERIC_ERROR;
+		goto err;
+	}
+	memset(new_entry, 0, sizeof(*new_entry));
+	new_entry->svc.listener_id = listnr->id;
+	new_entry->svc.sb_size = listnr->sb_size;
+	new_entry->CallbackFn = listnr->service_cmd_handler;
+
+	new_entry->svc.virt_sb_base = memalign(PAGE_SIZE, ROUNDUP(listnr->sb_size, PAGE_SIZE));
+	if (!new_entry->svc.virt_sb_base) {
+		dprintf(CRITICAL, "%s virt_sb_base malloc failed for size:%d\n", __func__, listnr->sb_size);
+		ret = GENERIC_ERROR;
+		goto err;
+	}
+	memset(new_entry->svc.virt_sb_base, 0, ROUNDUP(listnr->sb_size, PAGE_SIZE));
+	arch_clean_invalidate_cache_range((addr_t) new_entry->svc.virt_sb_base, ROUNDUP(listnr->sb_size, PAGE_SIZE));
+
+	req.qsee_cmd_id = QSEE_REGISTER_LISTENER;
+	req.listener_id = new_entry->svc.listener_id;
+	req.sb_len = new_entry->svc.sb_size;
+	/* convert to 32bit addr for tz */
+	req.sb_ptr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) new_entry->svc.virt_sb_base);
+
+	resp.result = QSEOS_RESULT_INCOMPLETE;
+
+	ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
+					sizeof(req), &resp, sizeof(resp));
+	if (ret) {
+		dprintf(CRITICAL, "qseecom_scm_call failed with err: %d\n", ret);
+		ret = GENERIC_ERROR;
+		goto err;
+	}
+	/* Add entry to Listener list */
+	list_add_tail(&qseecom.registered_listener_list_head, &new_entry->node);
+err:
+	if ((ret) &&
+			(ret != LISTENER_ALREADY_PRESENT_ERROR)) {
+		if ((new_entry) &&
+				(new_entry->svc.virt_sb_base))
+			free(new_entry->svc.virt_sb_base);
+		if (new_entry)
+			free(new_entry);
+	}
+	mutex_release(&qseecom.registered_listener_list_lock);
+	return ret;
+}
+
+/**
+* De-Registers a Listener Service with QSEE
+*
+* @param uint32_t listnr_id
+*   Pre-defined Listener ID to be de-registered
+*
+* @return int
+*   Status:
+*     0 - Success
+*     Negative value indicates failure.
+*/
+int qseecom_deregister_listener(uint32_t listnr_id)
+{
+	int ret = GENERIC_ERROR;
+	struct qseecom_registered_listener_list *new_entry = NULL;
+	struct qseecom_unregister_listener_ireq req;
+	struct qseecom_command_scm_resp resp;
+
+	mutex_acquire(&qseecom.global_data_lock);
+	if (!qseecom.qseecom_init_done) {
+		dprintf(CRITICAL, "%s qseecom_init not done\n",
+							__func__);
+		mutex_release(&qseecom.global_data_lock);
+		return ret;
+	}
+	mutex_release(&qseecom.global_data_lock);
+
+	mutex_acquire(&qseecom.registered_listener_list_lock);
+	dprintf(SPEW, "%s called\n", __func__);
+	new_entry = __qseecom_check_listener_exists(listnr_id);
+	if (!new_entry) {
+		dprintf(CRITICAL, "Service not present\n");
+		ret = GENERIC_ERROR;
+		goto err;
+	}
+
+	req.qsee_cmd_id = QSEE_DEREGISTER_LISTENER;
+	req.listener_id = listnr_id;
+	resp.result = QSEOS_RESULT_INCOMPLETE;
+
+	ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
+					sizeof(req), &resp, sizeof(resp));
+	if (ret) {
+		dprintf(CRITICAL, "scm_call() failed with err: %d (lstnr id=%d)\n",
+				ret, req.listener_id);
+		ret = GENERIC_ERROR;
+		goto err;
+	}
+
+	list_delete(&new_entry->node);
+
+err:
+	if (ret == 0) {
+		if (new_entry)
+			free(new_entry);
+	}
+	mutex_release(&qseecom.registered_listener_list_lock);
+	return ret;
+}
+
+int qseecom_tz_init()
+{
+	struct qsee_apps_region_info_ireq req;
+	struct qseecom_command_scm_resp resp;
+	int rc = GENERIC_ERROR;
+	/* register log buffer scm request */
+	void *buf = NULL;
+	/* Register app region with TZ */
+	req.qsee_cmd_id = QSEE_APP_REGION_NOTIFICATION;
+	req.addr = APP_REGION_ADDR;
+	req.size = APP_REGION_SIZE;
+	dprintf(ALWAYS, "secure app region addr=0x%x size=0x%x",
+					req.addr, req.size);
+	rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
+			&req, sizeof(req),
+			&resp, sizeof(resp));
+	dprintf(ALWAYS, "TZ App region notif returned with status:%d addr:%x size:%d\n",
+			rc, req.addr, req.size);
+	if (rc)
+		goto err;
+	buf = memalign(PAGE_SIZE, ROUNDUP(QSEE_LOG_BUF_SIZE, PAGE_SIZE));
+	if (!buf) {
+		rc = GENERIC_ERROR;
+		goto err;
+	}
+	memset(buf, 0, ROUNDUP(QSEE_LOG_BUF_SIZE, PAGE_SIZE));
+	logbuf_req.qsee_cmd_id = QSEE_REGISTER_LOG_BUF_COMMAND;
+	logbuf_req.phy_addr = (uint32_t)__qseecom_uvirt_to_kphys((uint32_t) buf);
+	logbuf_req.len = QSEE_LOG_BUF_SIZE;
+
+	rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
+			&logbuf_req, sizeof(logbuf_req),
+			&resp, sizeof(resp));
+	dprintf(ALWAYS, "TZ App log region register returned with status:%d addr:%x size:%d\n",
+			rc, logbuf_req.phy_addr, logbuf_req.len);
+	if (rc)
+		goto err;
+err:
+	if (!rc) {
+		qseecom.qseecom_tz_init_done = 1;
+		dprintf(ALWAYS, "Qseecom TZ Init Done in Appsbl\n");
+	}
+	return rc;
+}
+
+int qseecom_init()
+{
+	int rc = GENERIC_ERROR;
+
+	memset (&qseecom, 0, sizeof(struct qseecom_control));
+	dprintf(SPEW, "%s called\n", __func__);
+	mutex_init(&(qseecom.global_data_lock));
+	mutex_init(&(qseecom.registered_app_list_lock));
+	mutex_init(&(qseecom.registered_listener_list_lock));
+
+	list_initialize(&(qseecom.registered_app_list_head));
+	list_initialize(&(qseecom.registered_listener_list_head));
+
+	qseecom.qseos_version = QSEOS_VERSION_14;
+	rc = 0;
+
+	if (!rc) {
+		qseecom.qseecom_init_done = 1;
+		dprintf(ALWAYS, "Qseecom Init Done in Appsbl\n");
+	}
+	return rc;
+}
+
+int qseecom_exit()
+{
+	dprintf(SPEW, "%s called\n", __func__);
+
+	if (logbuf_req.phy_addr)
+		free((void *)logbuf_req.phy_addr);
+	qseecom.qseecom_init_done = 0;
+	dprintf(ALWAYS, "Qseecom De-Init Done in Appsbl\n");
+	return 0;
+}
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..846dc6e
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -498,6 +498,7 @@
 			$(LOCAL_DIR)/dev_tree.o \
 			$(LOCAL_DIR)/gpio.o \
 			$(LOCAL_DIR)/scm.o \
+			$(LOCAL_DIR)/qseecom_lk.o \
 			$(LOCAL_DIR)/qmp_usb30_phy.o \
 			$(LOCAL_DIR)/qusb2_phy.o \
 			$(LOCAL_DIR)/certificate.o \
@@ -533,3 +534,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
diff --git a/platform/msm_shared/scm.c b/platform/msm_shared/scm.c
index 681b238..88e6898 100644
--- a/platform/msm_shared/scm.c
+++ b/platform/msm_shared/scm.c
@@ -58,6 +58,11 @@
 bool scm_arm_support;
 static uint32_t scm_io_write(uint32_t address, uint32_t val);
 
+bool is_scm_armv8_support()
+{
+	return scm_arm_support;
+}
+
 static void scm_arm_support_available(uint32_t svc_id, uint32_t cmd_id)
 {
 	uint32_t ret;
@@ -1135,20 +1140,22 @@
 	register uint32_t r4 __asm__("r4") = x4;
 	register uint32_t r5 __asm__("r5") = x5;
 
-	__asm__ volatile(
-		__asmeq("%0", "r0")
-		__asmeq("%1", "r1")
-		__asmeq("%2", "r2")
-		__asmeq("%3", "r3")
-		__asmeq("%4", "r0")
-		__asmeq("%5", "r1")
-		__asmeq("%6", "r2")
-		__asmeq("%7", "r3")
-		__asmeq("%8", "r4")
-		__asmeq("%9", "r5")
-		"smc    #0  @ switch to secure world\n"
-		: "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
-		: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4), "r" (r5));
+	do {
+		__asm__ volatile(
+			__asmeq("%0", "r0")
+			__asmeq("%1", "r1")
+			__asmeq("%2", "r2")
+			__asmeq("%3", "r3")
+			__asmeq("%4", "r0")
+			__asmeq("%5", "r1")
+			__asmeq("%6", "r2")
+			__asmeq("%7", "r3")
+			__asmeq("%8", "r4")
+			__asmeq("%9", "r5")
+			"smc    #0  @ switch to secure world\n"
+			: "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3)
+			: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4), "r" (r5));
+	} while(r0 == 1);
 
 	if (ret)
 	{
@@ -1197,8 +1204,8 @@
 	return 0;
 }
 
-static bool secure_boot_enable = false;
-static bool wdog_debug_fuse_disable = false;
+static bool secure_boot_enabled = true;
+static bool wdog_debug_fuse_disabled = true;
 
 void scm_check_boot_fuses()
 {
@@ -1219,10 +1226,10 @@
 	if(!ret) {
 		/* Bit 0 - SECBOOT_ENABLE_CHECK */
 		if(resp & 0x1)
-			secure_boot_enable = true;
+			secure_boot_enabled = false;
 		/* Bit 2 - DEBUG_DISABLE_CHECK */
 		if(resp & 0x4)
-			wdog_debug_fuse_disable = true;
+			wdog_debug_fuse_disabled = false;
 	} else
 		dprintf(CRITICAL, "scm call to check secure boot fuses failed\n");
 }
@@ -1230,7 +1237,7 @@
 bool is_secure_boot_enable()
 {
 	scm_check_boot_fuses();
-	return secure_boot_enable;
+	return secure_boot_enabled;
 }
 
 static uint32_t scm_io_read(addr_t address)
@@ -1317,7 +1324,7 @@
 	scm_check_boot_fuses();
 
 	/* Make WDOG_DEBUG DISABLE scm call only in non-secure boot */
-	if(!(secure_boot_enable || wdog_debug_fuse_disable)) {
+	if(!(secure_boot_enabled || wdog_debug_fuse_disabled)) {
 		ret = scm_call2_atomic(SCM_SVC_BOOT, WDOG_DEBUG_DISABLE, 1, 0);
 		if(ret)
 			dprintf(CRITICAL, "Failed to disable the wdog debug \n");
diff --git a/platform/msm_shared/ucs.c b/platform/msm_shared/ucs.c
index 3e7563a..a1ab6f3 100644
--- a/platform/msm_shared/ucs.c
+++ b/platform/msm_shared/ucs.c
@@ -31,8 +31,7 @@
 #include <endian.h>
 #include <string.h>
 #include <utp.h>
-
-static int ucs_do_request_sense(struct ufs_dev *dev);
+#include <rpmb.h>
 
 int ucs_do_scsi_cmd(struct ufs_dev *dev, struct scsi_req_build_type *req)
 {
@@ -464,7 +463,7 @@
 	dprintf(CRITICAL,"----end of buffer---\n");
 }
 
-static int ucs_do_request_sense(struct ufs_dev *dev)
+int ucs_do_request_sense(struct ufs_dev *dev, uint8_t lun)
 {
 	STACKBUF_DMA_ALIGN(cdb, sizeof(struct scsi_sense_cdb));
 	struct scsi_req_build_type req_upiu;
@@ -488,7 +487,7 @@
 	req_upiu.data_buffer_addr  = (addr_t) buf;
 	req_upiu.data_len          = SCSI_SENSE_BUF_LEN;
 	req_upiu.flags			   = UPIU_FLAGS_READ;
-	req_upiu.lun			   = 0;
+	req_upiu.lun			   = lun;
 	req_upiu.dd			       = UTRD_TARGET_TO_SYSTEM;
 
 	if (ucs_do_scsi_cmd(dev, &req_upiu))
@@ -500,7 +499,9 @@
 	/* Flush buffer. */
 	arch_invalidate_cache_range((addr_t) buf, SCSI_INQUIRY_LEN);
 
+#if DEBUG_UFS
 	dump_sense_buffer(buf, SCSI_SENSE_BUF_LEN);
+#endif
 
 	return UFS_SUCCESS;
 }
diff --git a/platform/msm_shared/ufs.c b/platform/msm_shared/ufs.c
index aa5f90b..d3b7065 100644
--- a/platform/msm_shared/ufs.c
+++ b/platform/msm_shared/ufs.c
@@ -89,10 +89,17 @@
 	qgic_change_interrupt_cfg(UFS_IRQ, INTERRUPT_LVL_N_TO_N);
 }
 
-static void ufs_rpmb_init(struct ufs_dev *dev)
+void ufs_rpmb_init(struct ufs_dev *dev)
 {
 	int ret = 0;
 
+	/*
+	 * Perform request sense on lun to clear
+	 * attention pending, other wise all the read/write
+	 * operations would fail with check condition error
+	 */
+	ucs_do_request_sense(dev, UFS_WLUN_RPMB);
+
 	// calculate the size of rpmb partition in sectors
 	ret = dme_read_unit_desc(dev, UFS_WLUN_RPMB);
 	if (ret != UFS_SUCCESS)
diff --git a/platform/thulium/include/platform/iomap.h b/platform/thulium/include/platform/iomap.h
index ef58cfe..52faa44 100644
--- a/platform/thulium/include/platform/iomap.h
+++ b/platform/thulium/include/platform/iomap.h
@@ -165,6 +165,10 @@
 #define MPM2_MPM_PS_HOLD                     0x4AB000
 #define MPM2_MPM_SLEEP_TIMETICK_COUNT_VAL    0x4A3000
 
+/* QSEECOM: Secure app region notification */
+#define APP_REGION_ADDR 0x86600000
+#define APP_REGION_SIZE 0xd00000
+
 /* DRV strength for sdcc */
 #define SDC1_HDRV_PULL_CTL           (TLMM_BASE_ADDR + 0x0012C000)
 
@@ -189,4 +193,11 @@
 /* Dummy macro needed for compilation only */
 #define PLATFORM_QMP_OFFSET         0x0
 
+/* RPMB send receive buffer needs to be mapped
+ * as device memory, define the start address
+ * and size in MB
+ */
+#define RPMB_SND_RCV_BUF            0x8F200000
+#define RPMB_SND_RCV_BUF_SZ         0x1
+
 #endif
diff --git a/platform/thulium/platform.c b/platform/thulium/platform.c
index be0678c..def91a1 100644
--- a/platform/thulium/platform.c
+++ b/platform/thulium/platform.c
@@ -59,6 +59,7 @@
 	{    KERNEL_ADDR,       KERNEL_ADDR,       KERNEL_SIZE,      SCRATCH_MEMORY},
 	{    SCRATCH_ADDR,      SCRATCH_ADDR,      SCRATCH_SIZE,     SCRATCH_MEMORY},
 	{    MSM_SHARED_BASE,   MSM_SHARED_BASE,   MSM_SHARED_SIZE,  SCRATCH_MEMORY},
+	{    RPMB_SND_RCV_BUF,  RPMB_SND_RCV_BUF,  RPMB_SND_RCV_BUF_SZ,    IOMAP_MEMORY},
 };
 
 void platform_early_init(void)
diff --git a/project/thulium.mk b/project/thulium.mk
index 4bce478..4d9bb5e 100644
--- a/project/thulium.mk
+++ b/project/thulium.mk
@@ -19,6 +19,7 @@
 ENABLE_USB30_SUPPORT := 1
 ENABLE_QGIC3 := 1
 ENABLE_PARTIAL_GOODS_SUPPORT := 1
+ENABLE_RPMB_SUPPORT := 1
 
 DEFINES +=VIRTIO=1
 
@@ -37,6 +38,7 @@
 DEFINES += ABOOT_FORCE_KERNEL64_ADDR=0x80080000
 DEFINES += USB_RESET_FROM_CLK=1
 DEFINES += USE_BOOTDEV_CMDLINE=1
+DEFINES += USE_RPMB_FOR_DEVINFO=1
 
 #Disable thumb mode
 ENABLE_THUMB := false
diff --git a/target/msm8994/init.c b/target/msm8994/init.c
index 6dc9ce9..824bdc1 100644
--- a/target/msm8994/init.c
+++ b/target/msm8994/init.c
@@ -105,7 +105,7 @@
 }
 
 /* Return 1 if vol_up pressed */
-static int target_volume_up()
+int target_volume_up()
 {
 	uint8_t status = 0;
 	struct pm8x41_gpio gpio;
diff --git a/target/thulium/init.c b/target/thulium/init.c
index 28c6b2c..0d640db 100644
--- a/target/thulium/init.c
+++ b/target/thulium/init.c
@@ -55,6 +55,7 @@
 #include <qmp_phy.h>
 #include <sdhci_msm.h>
 #include <qusb2_phy.h>
+#include <rpmb.h>
 
 #define CE_INSTANCE             1
 #define CE_EE                   1
@@ -136,6 +137,22 @@
 		/* Disable HC mode before jumping to kernel */
 		sdhci_mode_disable(&dev->host);
 	}
+
+	if (is_sec_app_loaded())
+	{
+		if (unload_sec_app() < 0)
+		{
+			dprintf(CRITICAL, "Failed to unload App for rpmb\n");
+			ASSERT(0);
+		}
+	}
+
+	if (rpmb_uninit() < 0)
+	{
+		dprintf(CRITICAL, "RPMB uninit failed\n");
+		ASSERT(0);
+	}
+
 }
 
 static void set_sdc_power_ctrl()
@@ -238,6 +255,12 @@
 
 	/* Storage initialization is complete, read the partition table info */
 	mmc_read_partition_table(0);
+
+	if (rpmb_init() < 0)
+	{
+		dprintf(CRITICAL, "RPMB init failed\n");
+		ASSERT(0);
+	}
 }
 
 unsigned board_machtype(void)
diff --git a/target/thulium/rules.mk b/target/thulium/rules.mk
index 5ec0e88..982f4ee 100644
--- a/target/thulium/rules.mk
+++ b/target/thulium/rules.mk
@@ -5,11 +5,11 @@
 PLATFORM := thulium
 
 MEMBASE := 0x8F000000 # SDRAM
-MEMSIZE := 0x00100000 # 1MB
+MEMSIZE := 0x00200000 # 2MB
 
 BASE_ADDR    := 0x0000000
 
-SCRATCH_ADDR := 0x8F100000
+SCRATCH_ADDR := 0x8F300000
 SCRATCH_SIZE := 512
 KERNEL_ADDR  := 0x80000000
 KERNEL_SIZE  := 62