Merge "target: add support to skip panel configuration in LK"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 77fd8dc..aa02cda 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -90,6 +90,7 @@
 extern int get_target_boot_params(const char *cmdline, const char *part,
 				  char *buf, int buflen);
 
+void *info_buf;
 void write_device_info_mmc(device_info *dev);
 void write_device_info_flash(device_info *dev);
 static int aboot_save_boot_hash_mmc(uint32_t image_addr, uint32_t image_size);
@@ -1472,7 +1473,6 @@
 	return 0;
 }
 
-BUF_DMA_ALIGN(info_buf, BOOT_IMG_MAX_PAGE_SIZE);
 void write_device_info_mmc(device_info *dev)
 {
 	unsigned long long ptn = 0;
@@ -1551,10 +1551,15 @@
 
 void write_device_info_flash(device_info *dev)
 {
-	struct device_info *info = (void *) info_buf;
+	struct device_info *info = memalign(PAGE_SIZE, ROUNDUP(BOOT_IMG_MAX_PAGE_SIZE, PAGE_SIZE));
 	struct ptentry *ptn;
 	struct ptable *ptable;
-
+	if(info == NULL)
+	{
+		dprintf(CRITICAL, "Failed to allocate memory for device info struct\n");
+		ASSERT(0);
+	}
+	info_buf = info;
 	ptable = flash_get_ptable();
 	if (ptable == NULL)
 	{
@@ -1576,6 +1581,7 @@
 		dprintf(CRITICAL, "ERROR: Cannot write device info\n");
 			return;
 	}
+	free(info);
 }
 
 static int read_allow_oem_unlock(device_info *dev)
@@ -1651,10 +1657,15 @@
 
 void read_device_info_flash(device_info *dev)
 {
-	struct device_info *info = (void*) info_buf;
+	struct device_info *info = memalign(PAGE_SIZE, ROUNDUP(BOOT_IMG_MAX_PAGE_SIZE, PAGE_SIZE));
 	struct ptentry *ptn;
 	struct ptable *ptable;
-
+	if(info == NULL)
+	{
+		dprintf(CRITICAL, "Failed to allocate memory for device info struct\n");
+		ASSERT(0);
+	}
+	info_buf = info;
 	ptable = flash_get_ptable();
 	if (ptable == NULL)
 	{
@@ -1683,23 +1694,31 @@
 		write_device_info_flash(info);
 	}
 	memcpy(dev, info, sizeof(device_info));
+	free(info);
 }
 
 void write_device_info(device_info *dev)
 {
 	if(target_is_emmc_boot())
 	{
-		struct device_info *info = (void*) info_buf;
+		struct device_info *info = memalign(PAGE_SIZE, ROUNDUP(BOOT_IMG_MAX_PAGE_SIZE, PAGE_SIZE));
+		if(info == NULL)
+		{
+			dprintf(CRITICAL, "Failed to allocate memory for device info struct\n");
+			ASSERT(0);
+		}
+		info_buf = info;
 		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());
+			write_device_info_rpmb((void*) info, PAGE_SIZE);
 		else
 			write_device_info_mmc(info);
 #else
 		write_device_info_mmc(info);
 #endif
+		free(info);
 	}
 	else
 	{
@@ -1711,11 +1730,17 @@
 {
 	if(target_is_emmc_boot())
 	{
-		struct device_info *info = (void*) info_buf;
+		struct device_info *info = memalign(PAGE_SIZE, ROUNDUP(BOOT_IMG_MAX_PAGE_SIZE, PAGE_SIZE));
+		if(info == NULL)
+		{
+			dprintf(CRITICAL, "Failed to allocate memory for device info struct\n");
+			ASSERT(0);
+		}
+		info_buf = info;
 
 #if USE_RPMB_FOR_DEVINFO
 		if (is_secure_boot_enable())
-			read_device_info_rpmb((void*) info, mmc_get_device_blocksize());
+			read_device_info_rpmb((void*) info, PAGE_SIZE);
 		else
 			read_device_info_mmc(info);
 #else
@@ -1725,8 +1750,10 @@
 		if (memcmp(info->magic, DEVICE_MAGIC, DEVICE_MAGIC_SIZE))
 		{
 			memcpy(info->magic, DEVICE_MAGIC, DEVICE_MAGIC_SIZE);
-			info->is_unlocked = 0;
-			info->is_verified = 0;
+			if (is_secure_boot_enable())
+				info->is_unlocked = 0;
+			else
+				info->is_verified = 1;
 			info->is_tampered = 0;
 #if USER_BUILD_VARIANT
 			info->charger_screen_enabled = 1;
@@ -1736,6 +1763,7 @@
 			write_device_info(info);
 		}
 		memcpy(dev, info, sizeof(device_info));
+		free(info);
 	}
 	else
 	{
diff --git a/app/mmutest/mmu_test.c b/app/mmutest/mmu_test.c
new file mode 100644
index 0000000..216e73b
--- /dev/null
+++ b/app/mmutest/mmu_test.c
@@ -0,0 +1,94 @@
+/* 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 <sys/types.h>
+#include <debug.h>
+#include <arch/arm/mmu.h>
+#include <mmu.h>
+#include <string.h>
+
+/* COMMON memory - cacheable, write through */
+#define COMMON_MEMORY       (MMU_MEMORY_TYPE_NORMAL_WRITE_THROUGH | \
+                           MMU_MEMORY_AP_READ_WRITE | MMU_MEMORY_XN)
+
+#define MB (1024 * 1024)
+static mmu_section_t ramdump_mmu_section_table[] =
+{
+  /*        Physical addr,    Virtual addr,     Mapping type ,              Size (in MB),            Flags */
+	{    0xC0000000,        0xC0000000,       MMU_L2_NS_SECTION_MAPPING,  512,            COMMON_MEMORY},
+	{    0x100000000,       0xC0000000,       MMU_L2_NS_SECTION_MAPPING,  1024,            COMMON_MEMORY},
+	{    0x140000000,       0xC0000000,       MMU_L2_NS_SECTION_MAPPING,  484,            COMMON_MEMORY},
+};
+
+uint32_t vaddr[] = {0xc2300000, 0xcd000000, 0xde000000};
+uint64_t paddr[] = {0xc2300000, 0x10d000000, 0x15e000000};
+
+void ramdump_table_map()
+{
+	uint32_t i, j;
+	uint32_t table_sz = ARRAY_SIZE(ramdump_mmu_section_table);
+	char *ptr = NULL;
+	bool pass_access = true;
+	bool pass_conversion = true;
+	uint64_t paddr_v;
+	uint32_t vaddr_v;
+
+	for (i = 0 ; i < table_sz; i++)
+	{
+		arm_mmu_map_entry(&ramdump_mmu_section_table[i]);
+		vaddr_v = physical_to_virtual_mapping(paddr[i]);
+		if (vaddr_v != vaddr[i])
+			pass_conversion = false;
+		paddr_v = virtual_to_physical_mapping(vaddr[i]);
+		if (paddr_v != paddr[i])
+			pass_conversion = false;
+		ptr = (char *)(uintptr_t)ramdump_mmu_section_table[i].vaddress;
+
+		for (j = 0 ; j < (ramdump_mmu_section_table[i].size * MB)/5; j++)
+		{
+			strcpy(ptr, "hello");
+			ptr+=5;
+		}
+
+		ptr = (char *)(uintptr_t)ramdump_mmu_section_table[i].vaddress;
+
+		for (j = 0 ; j < (ramdump_mmu_section_table[i].size * MB)/5; j++)
+		{
+			if (memcmp((void *)ptr, "hello", 5))
+			{
+				pass_access = false;
+				break;
+			}
+			ptr+=5;
+		}
+		if (pass_access)
+			dprintf(CRITICAL, "LAPE TEST PASS for addr: 0x%llx\n", ramdump_mmu_section_table[i].paddress);
+	}
+		if (pass_conversion)
+			dprintf(CRITICAL, "Physical to virtual conversion TEST PASS\n");
+}
diff --git a/app/mmutest/rules.mk b/app/mmutest/rules.mk
new file mode 100644
index 0000000..78918a1
--- /dev/null
+++ b/app/mmutest/rules.mk
@@ -0,0 +1,6 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+INCLUDES += -I$(LK_TOP_DIR)/platform/msm_shared/include
+
+OBJS += \
+	$(LOCAL_DIR)/mmu_test.o
diff --git a/arch/arm/include/arch/arm.h b/arch/arm/include/arch/arm.h
index e056628..d5c3c5d 100644
--- a/arch/arm/include/arch/arm.h
+++ b/arch/arm/include/arch/arm.h
@@ -86,7 +86,9 @@
 void arm_write_ttbr(uint32_t val);
 void arm_write_dacr(uint32_t val);
 void arm_invalidate_tlb(void);
-
+void arm_write_mair0(uint32_t);
+void arm_write_mair1(uint32_t);
+void arm_write_ttbcr(uint32_t);
 void dump_fault_frame(struct arm_fault_frame *frame);
 
 #if defined(__cplusplus)
diff --git a/arch/arm/include/arch/arm/mmu.h b/arch/arm/include/arch/arm/mmu.h
index d5067eb..12bcd23 100644
--- a/arch/arm/include/arch/arm/mmu.h
+++ b/arch/arm/include/arch/arm/mmu.h
@@ -1,6 +1,8 @@
 /*
  * Copyright (c) 2008 Travis Geiselbrecht
  *
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files
  * (the "Software"), to deal in the Software without restriction,
@@ -33,6 +35,7 @@
 
 #if defined(ARM_ISA_ARMV6) | defined(ARM_ISA_ARMV7)
 
+#ifndef LPAE
 /* C, B and TEX[2:0] encodings without TEX remap */
                                                        /* TEX      |    CB    */
 #define MMU_MEMORY_TYPE_STRONGLY_ORDERED              ((0x0 << 12) | (0x0 << 2))
@@ -48,6 +51,68 @@
 #define MMU_MEMORY_AP_READ_WRITE    (0x3 << 10)
 
 #define MMU_MEMORY_XN               (0x1 << 4)
+#else /* LPAE */
+
+typedef enum
+{
+ /* Secure L1 section */
+  MMU_L1_SECTION_MAPPING = 0,
+
+  /* Non-secure L1 section */
+  MMU_L1_NS_SECTION_MAPPING,
+
+  /* Secure L2 section */
+  MMU_L2_SECTION_MAPPING,
+
+  /* Non-secure L2 section */
+  MMU_L2_NS_SECTION_MAPPING,
+
+  /* Secure L3 section */
+  MMU_L3_SECTION_MAPPING,
+
+  /* Non-secure L3 section */
+  MMU_L3_NS_SECTION_MAPPING,
+
+}mapping_type;
+
+
+#define ATTR_INDEX(x)         (x << 2) /* [4:2] - AttrIndx[2:0] of block descriptor */
+
+/* define the memory attributes for the block descriptors */
+
+#define MMU_MEMORY_TYPE_STRONGLY_ORDERED               ATTR_INDEX(0)
+#define MMU_MEMORY_TYPE_DEVICE_SHARED                  ATTR_INDEX(1) | (3 << 8) /*[9:8] - SH[1:0] - Shareability */
+#define MMU_MEMORY_TYPE_NORMAL                         ATTR_INDEX(2)
+#define MMU_MEMORY_TYPE_NORMAL_WRITE_THROUGH           ATTR_INDEX(7)
+#define MMU_MEMORY_TYPE_NORMAL_WRITE_BACK_ALLOCATE     ATTR_INDEX(4)
+#define MMU_MEMORY_TYPE_NORMAL_WRITE_BACK_NO_ALLOCATE  ATTR_INDEX(5)
+
+#define MMU_MEMORY_AP_READ_WRITE                       (1 << 6) /* Read/Write at any priveledge */
+#define MMU_MEMORY_XN                                  (1ULL << 54)
+#define MMU_MEMORY_PXN                                 (1ULL << 53)
+
+/* define the memory attributes:
+ * For LPAE, the block descriptor contains index into the MAIR registers.
+ * MAIR registers define the memory attributes. Below configuration is arrived based on
+ * the arm v7 manual section B4.1.104
+ */
+/* MAIR is 64 bit, with attrm[0..7], where m is 0..7
+ * Fill attrm[0..7] as below
+ * STRONG ORDERED                                        0000.0000
+ * DEVICE MEMORY                                         0000.0100
+ * normal memory, non cacheable                          0100.0100
+ * normal memory, WB, RA, nWA                            1110.1110
+ * normal memory, WB, RA, WA                             1111.1111
+ * normal memory, WB, nRA, nWA                           1100.1100
+ * normal memory, WT, RA, nWA                            1010.1010
+ * normal memory , WT, RA, WA                            1011.1011
+ */
+
+#define MAIR0                  0xee440400
+#define MAIR1                  0xbbaaccff
+#include <mmu.h>
+void arm_mmu_map_entry(mmu_section_t *entry);
+#endif /* LPAE */
 
 #else
 
@@ -56,7 +121,8 @@
 #endif
 
 void arm_mmu_map_section(addr_t paddr, addr_t vaddr, uint flags);
-
+uint64_t virtual_to_physical_mapping(uint32_t vaddr);
+uint32_t physical_to_virtual_mapping(uint64_t paddr);
 
 #if defined(__cplusplus)
 }
diff --git a/arch/arm/mmu_lpae.c b/arch/arm/mmu_lpae.c
new file mode 100644
index 0000000..ddf66fd
--- /dev/null
+++ b/arch/arm/mmu_lpae.c
@@ -0,0 +1,323 @@
+/* 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 <debug.h>
+#include <sys/types.h>
+#include <compiler.h>
+#include <arch.h>
+#include <arch/arm.h>
+#include <arch/defines.h>
+#include <arch/arm/mmu.h>
+#include <mmu.h>
+#include <platform.h>
+
+#if ARM_WITH_MMU
+
+#define LPAE_SIZE               (1ULL << 40)
+#define LPAE_MASK               (LPAE_SIZE - 1)
+#define L1_PT_INDEX             0x7FC0000000
+#define PT_TABLE_DESC_BIT       0x2
+#define SIZE_1GB                (0x400000000UL)
+#define SIZE_2MB                (0x200000)
+#define MMU_L2_PT_SIZE          512
+#define MMU_PT_BLOCK_DESCRIPTOR 0x1
+#define MMU_PT_TABLE_DESCRIPTOR 0x3
+#define MMU_AP_FLAG             (0x1 << 10)
+#define L2_PT_MASK              0xFFFFE00000
+#define L2_INDEX_MASK           0x3FE00000
+
+uint64_t mmu_l1_pagetable[L1_PT_SZ] __attribute__ ((aligned(4096))); /* Max is 8 */
+uint64_t mmu_l2_pagetable[L2_PT_SZ*MMU_L2_PT_SIZE] __attribute__ ((aligned(4096))); /* Macro from target code * 512 */
+uint64_t avail_l2_pt = L2_PT_SZ;
+uint64_t *empty_l2_pt = mmu_l2_pagetable;
+
+/************************************************************/
+/* MAP 2MB granules in 1GB section in L2 page table */
+/***********************************************************/
+
+static void mmu_map_l2_entry(mmu_section_t *block)
+{
+	uint64_t *l2_pt = NULL;
+	uint64_t  address_start;
+	uint64_t  address_end;
+	uint64_t  p_addr;
+
+	/* First initialize the first level descriptor for each 1 GB
+	 * Bits[47:12] provide the physical base address of the level 2 page table
+	 *
+	 *    ________________________________________________________________________________
+	 *   |  |     |  |   |       |        |                            |       |          |
+	 *   |63|62-61|60| 59|58---52|51----40|39------------------------12|11----2|1------- 0|
+	 *   |NS| AP  |XN|PXN|Ignored|UNK|SBZP|Next-level table addr[39:12]|Ignored|Descriptor|
+	 *   |__|_____|__|___|_______|________|____________________________|_______|__________|
+	 * NS: Used only in secure state
+	 * AP: Access protection
+	 */
+
+	/* Convert the virtual address[38:30] into an index of the L1 page table */
+	address_start = (block->vaddress & LPAE_MASK) >> 30;
+
+	 /* Check if this 1GB entry has L2 page table mapped already
+	 * if L1 entry hasn't mapped any L2 page table, allocate a L2 page table for it
+	 */
+
+	if((mmu_l1_pagetable[address_start] & PT_TABLE_DESC_BIT) == 0)
+	{
+		ASSERT(avail_l2_pt);
+
+		/* Get the first l2 empty page table and fill in the L1 PTE with a table descriptor,
+		 * The l2_pt address bits 12:39 are used for L1 PTE entry
+		 */
+		l2_pt = empty_l2_pt;
+
+		/* Bits 39.12 of the page table address are mapped into the L1 PTE entry */
+		mmu_l1_pagetable[address_start] = ((uint64_t)(uintptr_t)l2_pt & 0x0FFFFFFF000) | MMU_PT_TABLE_DESCRIPTOR;
+
+		/* Advance pointer to next empty l2 page table */
+		empty_l2_pt += MMU_L2_PT_SIZE;
+		avail_l2_pt--;
+	}
+	else
+	{
+		/* Entry has L2 page table mapped already, so just get the existing L2 page table address */
+		l2_pt = (uint64_t *) (uintptr_t)(mmu_l1_pagetable[address_start] & 0xFFFFFFF000);
+    }
+
+	/* Get the physical address of 2MB sections, bits 21:39 are used to populate the L2 entry */
+	p_addr = block->paddress & L2_PT_MASK;
+
+	/* Start index into the L2 page table for this section using the virtual address[29:21]*/
+	address_start  = (block->vaddress & L2_INDEX_MASK) >> 21;
+
+	/* The end index for the given section. size given is in MB convert it to number of 2MB segments */
+	address_end = address_start + ((block->size) >> 1);
+
+	/*
+	 *      ___________________________________________________________________________________________________________________
+	 *     |       |        |  |   |    |        |                  |        |  |  |       |       |  |             |          |
+	 *     |63---59|58----55|54|53 |52  |51----40|39--------------21|20----12|11|10|9     8|7     6|5 |4-----------2|  1   0   |
+	 *     |Ignored|Reserved|XN|PXN|Cont|UNK|SBZP|Output addr[39:21]|UNK|SBZP|nG|AF|SH[1:0]|AP[2:1]|NS|AttrIndx[2:0]|Descriptor|
+	 *     |_______|________|__|___|____|________|__________________|________|__|__|_______|_______|__|_____________|__________|
+	 */
+
+	/* Map all the 2MB segments in the 1GB section */
+	while (address_start < address_end)
+	{
+		l2_pt[address_start] =  (p_addr) | MMU_PT_BLOCK_DESCRIPTOR | MMU_AP_FLAG | block->flags;
+		address_start++;
+		/* Increment to the next 2MB segment in current L2 page table*/
+		p_addr += SIZE_2MB;
+		arm_invalidate_tlb();
+	}
+}
+
+/************************************************************/
+/* MAP 1GB granules in L1 page table */
+/***********************************************************/
+static void mmu_map_l1_entry(mmu_section_t *block)
+{
+	uint64_t address_start;
+	uint64_t address_end;
+	uint64_t p_addr;
+
+	/* Convert our base address into an index into the page table */
+	address_start = (block->vaddress & LPAE_MASK) >> 30;
+
+	/* Get the end address into the page table, size is in MB, convert to GB for L1 mapping */
+	address_end = address_start + ((block->size) >> 10);
+
+	/* bits 38:30 provide the physical base address of the section */
+	p_addr = block->paddress & L1_PT_INDEX;
+
+	while(address_start < address_end)
+	{
+	 /*
+	 *    A Block descriptor for first stage, level one is as follows (Descriptor = 0b01):
+	 *         ___________________________________________________________________________________________________________________
+	 *        |       |        |  |	  |    |        |                  |        |  |  |       |       |  |             |          |
+	 *        |63---59|58----55|54|53 |52  |51----40|39--------------30|n-1 --12|11|10|9     8|7     6|5 |4-----------2|  1   0   |
+	 *        |Ignored|Reserved|XN|PXN|Cont|UNK/SBZP|Output addr[47:30]|UNK/SBZP|nG|AF|SH[1:0]|AP[2:1]|NS|AttrIndx[2:0]|Descriptor|
+	 *        |_______|________|__|___|____|________|__________________|________|__|__|_______|_______|__|_____________|__________|
+	 */
+
+		mmu_l1_pagetable[address_start] =  (p_addr) | block->flags | MMU_AP_FLAG | MMU_PT_BLOCK_DESCRIPTOR;
+
+		p_addr += SIZE_1GB; /* Point to next level */
+		address_start++;
+		arm_invalidate_tlb();
+	}
+}
+
+void arm_mmu_map_entry(mmu_section_t *entry)
+{
+	ASSERT(entry);
+
+	if (entry->type == MMU_L1_NS_SECTION_MAPPING)
+		mmu_map_l1_entry(entry);
+	else if(entry->type == MMU_L2_NS_SECTION_MAPPING)
+		mmu_map_l2_entry(entry);
+	else
+		dprintf(CRITICAL, "Invalid mapping type in the mmu table: %d\n", entry->type);
+}
+
+void arm_mmu_init(void)
+{
+	/* set some mmu specific control bits:
+	 * access flag disabled, TEX remap disabled, mmu disabled
+	 */
+	arm_write_cr1(arm_read_cr1() & ~((1<<29)|(1<<28)|(1<<0)));
+
+	platform_init_mmu_mappings();
+
+	/* set up the translation table base */
+	arm_write_ttbr((uint32_t)mmu_l1_pagetable);
+
+	/* set up the Memory Attribute Indirection Registers 0 and 1 */
+	arm_write_mair0(MAIR0);
+	arm_write_mair1(MAIR1);
+
+	/* TTBCR.EAE = 1 */
+	arm_write_ttbcr(0x80000000);
+
+	/* Enable TRE */
+	arm_write_cr1(arm_read_cr1() | (1<<28));
+
+	/* turn on the mmu */
+	arm_write_cr1(arm_read_cr1() | 0x1);
+}
+
+void arch_disable_mmu(void)
+{
+	/* Ensure all memory access are complete
+	 * before disabling MMU
+	 */
+	dsb();
+	arm_write_cr1(arm_read_cr1() & ~(1<<0));
+	arm_invalidate_tlb();
+}
+
+uint64_t virtual_to_physical_mapping(uint32_t vaddr)
+{
+	uint32_t l1_index;
+	uint64_t *l2_pt = NULL;
+	uint32_t l2_index;
+	uint32_t offset = 0;
+	uint64_t paddr = 0;
+
+	/* Find the L1 index from virtual address */
+	l1_index = (vaddr & LPAE_MASK) >> 30;
+
+	if ((mmu_l1_pagetable[l1_index] & MMU_PT_TABLE_DESCRIPTOR) == MMU_PT_TABLE_DESCRIPTOR)
+	{
+		/* Get the l2 page table address */
+		l2_pt = (uint64_t *) (uintptr_t) (mmu_l1_pagetable[l1_index] & 0x0FFFFFFF000);
+		/* Get the l2 index from virtual address */
+		l2_index = (vaddr & L2_INDEX_MASK) >> 21;
+		/* Calculate the offset from vaddr. */
+		offset = vaddr & 0x1FFFFF;
+		/* Get the physical address bits from 21 to 39 */
+		paddr = (l2_pt[l2_index] & L2_PT_MASK) + offset;
+	} else if ((mmu_l1_pagetable[l1_index] & MMU_PT_TABLE_DESCRIPTOR) == MMU_PT_BLOCK_DESCRIPTOR)
+	{
+		/* Calculate the offset from bits 0 to 30 */
+		offset = vaddr & 0x3FFFFFFF;
+		/* Return the entry from l1 page table */
+		paddr = (mmu_l1_pagetable[l1_index] & L1_PT_INDEX) + offset;
+	} else
+	{
+		ASSERT(0);
+	}
+
+	return paddr;
+}
+
+uint32_t physical_to_virtual_mapping(uint64_t paddr)
+{
+	uint32_t i, j;
+	uint32_t vaddr_index = 0;
+	uint32_t vaddr = 0;
+	uint64_t paddr_base_l1;
+	uint64_t paddr_base_l2;
+	uint64_t *l2_pt = NULL;
+	bool l1_index_found = false;
+	uint32_t l1_index = 0;
+	uint32_t offset = 0;
+
+	/* Traverse through the L1 page table to look for block descriptor */
+	for (i = 0; i < L1_PT_SZ; i++)
+	{
+		/* Find the L1 page table index */
+		paddr_base_l1 = paddr & L1_PT_INDEX;
+
+		/* If the L1 index is unused continue */
+		if ((mmu_l1_pagetable[i] & MMU_PT_TABLE_DESCRIPTOR) == 0)
+			continue;
+
+		/* If Its a block entry, find the matching entry and return the index */
+		if ((mmu_l1_pagetable[i] & MMU_PT_TABLE_DESCRIPTOR) == MMU_PT_BLOCK_DESCRIPTOR)
+		{
+			if ((mmu_l1_pagetable[i] & L1_PT_INDEX) == paddr_base_l1)
+			{
+				offset = paddr - paddr_base_l1;
+				vaddr_index = i;
+				l1_index_found = true;
+				goto end;
+			} /* If the entry is table, extract table address */
+		} else if ((mmu_l1_pagetable[i] & MMU_PT_TABLE_DESCRIPTOR) == MMU_PT_TABLE_DESCRIPTOR)
+		{
+			l1_index = i;
+			l2_pt = (uint64_t *) (uintptr_t) (mmu_l1_pagetable[l1_index] & 0x0FFFFFFF000);
+			paddr_base_l2 = paddr & L2_PT_MASK;
+			/* Search the table to find index in L2 page table */
+			for (j = 0; j < MMU_L2_PT_SIZE; j++)
+			{
+				if (paddr_base_l2 == (l2_pt[j] & L2_PT_MASK))
+				{
+					vaddr_index = j;
+					offset = paddr - paddr_base_l2;
+					goto end;
+				}
+			}
+		}
+	}
+	/* If we reach here, that means the addrss is either no mapped or invalid request */
+	dprintf(CRITICAL, "The address %llx is not mapped\n", paddr);
+	ASSERT(0);
+
+end:
+	/* Convert the index into the virtual address */
+	if (l1_index_found)
+		vaddr = (vaddr_index << 30);
+	else
+		vaddr = ((vaddr_index << 21) & L2_INDEX_MASK) + (l1_index << 30);
+
+	vaddr += offset;
+
+	return vaddr;
+}
+#endif // ARM_WITH_MMU
diff --git a/arch/arm/ops.S b/arch/arm/ops.S
index 4cfd180..c97a4d6 100644
--- a/arch/arm/ops.S
+++ b/arch/arm/ops.S
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2008 Travis Geiselbrecht
  *
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files
@@ -245,6 +245,8 @@
 
 /* void arm_invalidate_tlb(void) */
 FUNCTION(arm_invalidate_tlb)
+	dsb
+	isb
 	mov		r0, #0
 	mcr	p15, 0, r0, c8, c7, 0
 #if ARM_CPU_CORTEX_A8
@@ -287,3 +289,15 @@
 	mov		r0, #0
 #endif
 	bx		lr
+
+FUNCTION(arm_write_mair0)
+	mcr p15, 0, r0, c10, c2, 0
+	bx	lr
+
+FUNCTION(arm_write_mair1)
+	mcr p15, 0, r0, c10, c2, 1
+	bx lr
+
+FUNCTION(arm_write_ttbcr)
+	mcr p15, 0, r0, c2, c0, 2
+	bx lr
diff --git a/arch/arm/rules.mk b/arch/arm/rules.mk
index f45a6eb..7e3ace0 100644
--- a/arch/arm/rules.mk
+++ b/arch/arm/rules.mk
@@ -94,10 +94,15 @@
 	$(LOCAL_DIR)/ops.o \
 	$(LOCAL_DIR)/exceptions.o \
 	$(LOCAL_DIR)/faults.o \
-	$(LOCAL_DIR)/mmu.o \
 	$(LOCAL_DIR)/thread.o \
 	$(LOCAL_DIR)/dcc.o
 
+ifeq ($(ENABLE_LPAE_SUPPORT), 1)
+OBJS +=  $(LOCAL_DIR)/mmu_lpae.o
+else
+OBJS +=  $(LOCAL_DIR)/mmu.o
+endif
+
 # set the default toolchain to arm eabi and set a #define
 TOOLCHAIN_PREFIX ?= arm-eabi-
 ifeq ($(TOOLCHAIN_PREFIX),arm-none-linux-gnueabi-)
diff --git a/dev/gcdb/display/include/panel_truly_1080p_cmd.h b/dev/gcdb/display/include/panel_truly_1080p_cmd.h
index 8ed9c7e..6b98500 100644
--- a/dev/gcdb/display/include/panel_truly_1080p_cmd.h
+++ b/dev/gcdb/display/include/panel_truly_1080p_cmd.h
@@ -80,12 +80,12 @@
 
 
 static char truly_1080p_cmd_on_cmd4[] = {
-	0x55, 0x03, 0x15, 0x80,
+	0x55, 0x00, 0x15, 0x80,
 };
 
 
 static char truly_1080p_cmd_on_cmd5[] = {
-	0x29, 0x00, 0x05, 0x80,
+	0x11, 0x00, 0x05, 0x80,
 };
 
 
@@ -225,7 +225,7 @@
 
 
 static char truly_1080p_cmd_on_cmd21[] = {
-	0x11, 0x00, 0x05, 0x80,
+	0x29, 0x00, 0x05, 0x80,
 };
 
 
@@ -235,7 +235,7 @@
 	{ 0x4 , truly_1080p_cmd_on_cmd2, 0x00},
 	{ 0x4 , truly_1080p_cmd_on_cmd3, 0x00},
 	{ 0x4 , truly_1080p_cmd_on_cmd4, 0x00},
-	{ 0x4 , truly_1080p_cmd_on_cmd5, 0x14},
+	{ 0x4 , truly_1080p_cmd_on_cmd5, 0x78},
 	{ 0x4 , truly_1080p_cmd_on_cmd6, 0x00},
 	{ 0xc , truly_1080p_cmd_on_cmd7, 0x00},
 	{ 0x8 , truly_1080p_cmd_on_cmd8, 0x00},
@@ -251,7 +251,7 @@
 	{ 0xc , truly_1080p_cmd_on_cmd18, 0x00},
 	{ 0x24 , truly_1080p_cmd_on_cmd19, 0x00},
 	{ 0x18 , truly_1080p_cmd_on_cmd20, 0xc8},
-	{ 0x4 , truly_1080p_cmd_on_cmd21, 0x78},
+	{ 0x4 , truly_1080p_cmd_on_cmd21, 0x14},
 };
 
 #define TRULY_1080P_CMD_ON_COMMAND 22
diff --git a/dev/gcdb/display/include/panel_truly_1080p_video.h b/dev/gcdb/display/include/panel_truly_1080p_video.h
index 9cde8d4..5352d3c 100755
--- a/dev/gcdb/display/include/panel_truly_1080p_video.h
+++ b/dev/gcdb/display/include/panel_truly_1080p_video.h
@@ -74,11 +74,11 @@
 
 
 static char truly_1080p_video_on_cmd3[] = {
-0x55, 0x03, 0x15, 0x80, };
+0x55, 0x00, 0x15, 0x80, };
 
 
 static char truly_1080p_video_on_cmd4[] = {
-0x29, 0x00, 0x05, 0x80, };
+0x11, 0x00, 0x05, 0x80, };
 
 
 static char truly_1080p_video_on_cmd5[] = {
@@ -202,7 +202,7 @@
 
 
 static char truly_1080p_video_on_cmd20[] = {
-0x11, 0x00, 0x05, 0x80, };
+0x29, 0x00, 0x05, 0x80, };
 
 
 static struct mipi_dsi_cmd truly_1080p_video_on_command[] = {
diff --git a/include/dev/udc.h b/include/dev/udc.h
index 31d9755..7dc16c0 100644
--- a/include/dev/udc.h
+++ b/include/dev/udc.h
@@ -102,12 +102,15 @@
 #define SET_INTERFACE        11
 #define SYNCH_FRAME          12
 #define SET_SEL              48
+#define SET_ISOCH_DELAY      49
 
 #define TYPE_DEVICE          1
 #define TYPE_CONFIGURATION   2
 #define TYPE_STRING          3
 #define TYPE_INTERFACE       4
 #define TYPE_ENDPOINT        5
+#define TYPE_DEVICE_QUALIFIER          6
+#define TYPE_OTHER_SPEED_CONFIG        7
 #define TYPE_BOS             15
 #define TYPE_DEVICE_CAP      16
 #define TYPE_SS_EP_COMP      48
@@ -118,9 +121,14 @@
 #define INTERFACE_WRITE      0x01
 #define ENDPOINT_READ        0x82
 #define ENDPOINT_WRITE       0x02
+#define TEST_MODE            0x02
 
+#define TEST_J               0x0100
+#define TEST_K               0x0200
 #define TEST_SE0_NAK		 0x0300
 #define TEST_PACKET          0x0400
+#define TEST_FORCE_ENABLE    0x0500
+
 #define PORTSC_PTC           (0xF << 16)
 #define PORTSC_PTC_SE0_NAK	 (0x03 << 16)
 #define PORTSC_PTC_TST_PKT   (0x4 << 16)
diff --git a/platform/msm8996/include/platform/iomap.h b/platform/msm8996/include/platform/iomap.h
index a4e7d54..2244632 100644
--- a/platform/msm8996/include/platform/iomap.h
+++ b/platform/msm8996/include/platform/iomap.h
@@ -191,8 +191,8 @@
  * as device memory, define the start address
  * and size in MB
  */
-#define RPMB_SND_RCV_BUF            0x90D00000
-#define RPMB_SND_RCV_BUF_SZ         0x1
+#define RPMB_SND_RCV_BUF            0x90F00000
+#define RPMB_SND_RCV_BUF_SZ         0x2
 
 #define TCSR_BOOT_MISC_DETECT       0x007B3000
 
diff --git a/platform/msm8996/platform.c b/platform/msm8996/platform.c
index d0ab86d..6e04abf 100644
--- a/platform/msm8996/platform.c
+++ b/platform/msm8996/platform.c
@@ -32,8 +32,8 @@
 #include <qgic.h>
 #include <qtimer.h>
 #include <platform/clock.h>
-#include <mmu.h>
 #include <arch/arm/mmu.h>
+#include <mmu.h>
 #include <smem.h>
 #include <board.h>
 
@@ -46,20 +46,31 @@
 
 /* Peripherals - non-shared device */
 #define IOMAP_MEMORY      (MMU_MEMORY_TYPE_DEVICE_SHARED | \
-                           MMU_MEMORY_AP_READ_WRITE | MMU_MEMORY_XN)
+                           MMU_MEMORY_AP_READ_WRITE | MMU_MEMORY_XN | MMU_MEMORY_PXN)
 
 /* SCRATCH memory - cacheable, write through */
 #define SCRATCH_MEMORY       (MMU_MEMORY_TYPE_NORMAL_WRITE_THROUGH | \
                            MMU_MEMORY_AP_READ_WRITE | MMU_MEMORY_XN)
 
-static mmu_section_t mmu_section_table[] = {
-/*       Physical addr,    Virtual addr,     Size (in MB),       Flags */
-	{    MEMBASE,           MEMBASE,          (MEMSIZE / MB),    LK_MEMORY},
-	{    MSM_IOMAP_BASE,    MSM_IOMAP_BASE,    MSM_IOMAP_SIZE,   IOMAP_MEMORY},
-	{    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},
+/* COMMON memory - cacheable, write through */
+#define COMMON_MEMORY       (MMU_MEMORY_TYPE_NORMAL_WRITE_THROUGH | \
+                           MMU_MEMORY_AP_READ_WRITE | MMU_MEMORY_XN)
+
+
+static mmu_section_t default_mmu_section_table[] =
+{
+/*        Physical addr,    Virtual addr,     Mapping type ,              Size (in MB),            Flags */
+    {    0x00000000,        0x00000000,       MMU_L1_NS_SECTION_MAPPING,  1024,                IOMAP_MEMORY},
+    {    KERNEL_ADDR,       KERNEL_ADDR,      MMU_L2_NS_SECTION_MAPPING,  KERNEL_SIZE,         COMMON_MEMORY},
+    {    MEMBASE,           MEMBASE,          MMU_L2_NS_SECTION_MAPPING,  (MEMSIZE / MB),      LK_MEMORY},
+    {    SCRATCH_ADDR,      SCRATCH_ADDR,     MMU_L2_NS_SECTION_MAPPING,  SCRATCH_SIZE,        SCRATCH_MEMORY},
+    {    MSM_SHARED_BASE,   MSM_SHARED_BASE,  MMU_L2_NS_SECTION_MAPPING,  MSM_SHARED_SIZE,     COMMON_MEMORY},
+    {    RPMB_SND_RCV_BUF,  RPMB_SND_RCV_BUF, MMU_L2_NS_SECTION_MAPPING,  RPMB_SND_RCV_BUF_SZ, IOMAP_MEMORY},
+};
+
+static mmu_section_t dload_mmu_section_table[] =
+{
+    { 0x85800000, 0x85800000, MMU_L2_NS_SECTION_MAPPING, 178, COMMON_MEMORY},
 };
 
 void platform_early_init(void)
@@ -94,37 +105,30 @@
 /* Setup memory for this platform */
 void platform_init_mmu_mappings(void)
 {
-	uint32_t i;
-	uint32_t sections;
-	uint32_t table_size = ARRAY_SIZE(mmu_section_table);
+	int i;
+	int table_sz = ARRAY_SIZE(default_mmu_section_table);
 
-	/* Configure the MMU page entries for memory read from the
-	   mmu_section_table */
-	for (i = 0; i < table_size; i++)
+	for (i = 0 ; i < table_sz; i++)
+		arm_mmu_map_entry(&default_mmu_section_table[i]);
+
+	if (scm_device_enter_dload())
 	{
-		sections = mmu_section_table[i].num_of_sections;
+		/* TZ & Hyp memory can be mapped only while entering the download mode */
+		table_sz = ARRAY_SIZE(dload_mmu_section_table);
 
-		while (sections--)
-		{
-			arm_mmu_map_section(mmu_section_table[i].paddress +
-								sections * MB,
-								mmu_section_table[i].vaddress +
-								sections * MB,
-								mmu_section_table[i].flags);
-		}
+		for (i = 0 ; i < table_sz; i++)
+			arm_mmu_map_entry(&dload_mmu_section_table[i]);
 	}
 }
 
 addr_t platform_get_virt_to_phys_mapping(addr_t virt_addr)
 {
-	/* Using 1-1 mapping on this platform. */
-	return virt_addr;
+	return virtual_to_physical_mapping(virt_addr);
 }
 
 addr_t platform_get_phys_to_virt_mapping(addr_t phys_addr)
 {
-	/* Using 1-1 mapping on this platform. */
-	return phys_addr;
+	return physical_to_virtual_mapping(phys_addr);
 }
 
 uint32_t platform_get_sclk_count(void)
diff --git a/platform/msm_shared/include/mmu.h b/platform/msm_shared/include/mmu.h
index 6d001e7..d70872e 100644
--- a/platform/msm_shared/include/mmu.h
+++ b/platform/msm_shared/include/mmu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011, 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
@@ -30,12 +30,23 @@
 #define __MSM_SHARED_MMU_H__
 
 #include <sys/types.h>
+#include <arch/arm/mmu.h>
 
+#ifdef LPAE
+typedef struct {
+	uint64_t paddress;
+	uint64_t vaddress;
+	mapping_type type;
+	uint64_t size;
+	uint64_t flags;
+} mmu_section_t;
+#else
 typedef struct {
 	addr_t paddress;
 	addr_t vaddress;
 	uint32_t num_of_sections;
 	uint32_t flags;
 } mmu_section_t;
+#endif
 
 #endif
diff --git a/platform/msm_shared/include/scm.h b/platform/msm_shared/include/scm.h
index 2cdca66..95f4f46 100644
--- a/platform/msm_shared/include/scm.h
+++ b/platform/msm_shared/include/scm.h
@@ -235,6 +235,7 @@
 #define SVC_MEMORY_PROTECTION       0x0C
 #define TZ_SVC_CRYPTO               0x0A
 #define SCM_SVC_INFO                0x06
+#define TZ_SVC_DLOAD_MODE           0x3
 
 /*Service specific command IDs */
 #define ERR_FATAL_ENABLE            0x0
@@ -461,4 +462,5 @@
 bool is_scm_armv8_support();
 
 int scm_dload_mode(int mode);
+int scm_device_enter_dload();
 #endif
diff --git a/platform/msm_shared/rpmb/rpmb.c b/platform/msm_shared/rpmb/rpmb.c
index de67c46..36bacab 100644
--- a/platform/msm_shared/rpmb/rpmb.c
+++ b/platform/msm_shared/rpmb/rpmb.c
@@ -140,7 +140,9 @@
 	read_rsp.cmd_id = CLIENT_CMD_READ_LK_DEVICE_STATE;
 
 	/* Read the device info */
+	arch_clean_invalidate_cache_range((addr_t) info, sz);
 	ret = qseecom_send_command(app_handle, (void*) &read_req, sizeof(read_req), (void*) &read_rsp, sizeof(read_rsp));
+	arch_invalidate_cache_range((addr_t) info, sz);
 
 	if (ret < 0 || read_rsp.status < 0)
 	{
@@ -165,7 +167,9 @@
 	write_rsp.cmd_id = CLIENT_CMD_WRITE_LK_DEVICE_STATE;
 
 	/* Write the device info */
+	arch_clean_invalidate_cache_range((addr_t) info, sz);
 	ret = qseecom_send_command(app_handle, (void *)&write_req, sizeof(write_req), (void *)&write_rsp, sizeof(write_rsp));
+	arch_invalidate_cache_range((addr_t) info, sz);
 
 	if (ret < 0 || write_rsp.status < 0)
 	{
diff --git a/platform/msm_shared/scm.c b/platform/msm_shared/scm.c
index 5179e8e..cdb0282 100644
--- a/platform/msm_shared/scm.c
+++ b/platform/msm_shared/scm.c
@@ -1334,4 +1334,22 @@
 
 	return ret;
 }
+
+bool scm_device_enter_dload()
+{
+	uint32_t ret = 0;
+
+	scmcall_arg scm_arg = {0};
+	scmcall_ret scm_ret = {0};
+
+	scm_arg.x0 = MAKE_SIP_SCM_CMD(TZ_SVC_DLOAD_MODE, SCM_DLOAD_CMD);
+	ret = scm_call2(&scm_arg, &scm_ret);
+	if (ret)
+		dprintf(CRITICAL, "SCM call to check dload mode failed: %x\n", ret);
+
+	if (!ret && (scm_io_read(TCSR_BOOT_MISC_DETECT) == SCM_DLOAD_MODE))
+		return true;
+
+	return false;
+}
 #endif
diff --git a/platform/msm_shared/sdhci_msm.c b/platform/msm_shared/sdhci_msm.c
index f4c5c8c..eaeb744 100644
--- a/platform/msm_shared/sdhci_msm.c
+++ b/platform/msm_shared/sdhci_msm.c
@@ -147,14 +147,7 @@
 	uint32_t caps = 0;
 	uint32_t version;
 
-	/* Disable HC mode */
-	RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), SDHCI_HC_START_BIT, SDHCI_HC_WIDTH, 0);
-
-	/* Core power reset */
-	RMWREG32((config->pwrctl_base + SDCC_MCI_POWER), CORE_SW_RST_START, CORE_SW_RST_WIDTH, 1);
-
-	/* Wait for the core power reset to complete*/
-	 mdelay(1);
+	REG_WRITE32(host, 0xA1C, SDCC_VENDOR_SPECIFIC_FUNC);
 
 	/* Enable sdhc mode */
 	RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), SDHCI_HC_START_BIT, SDHCI_HC_WIDTH, SDHCI_HC_MODE_EN);
diff --git a/platform/msm_shared/usb30_dwc.c b/platform/msm_shared/usb30_dwc.c
index 9e4a59a..564d1c9 100644
--- a/platform/msm_shared/usb30_dwc.c
+++ b/platform/msm_shared/usb30_dwc.c
@@ -1056,6 +1056,13 @@
 			 * something wrong in fsm implementation.
 			 */
 			ASSERT(ep->state == EP_STATE_XFER_IN_PROG);
+			if (dev->is_test_mode)
+			{
+				/* Write DCTL register with test mode value */
+				dwc_device_enter_test_mode(dev);
+				dprintf(INFO, "Device entered test mode, please reset the device once testing is finished\n");
+				break;
+			}
 
 			ep->state = EP_STATE_INACTIVE;
 
diff --git a/platform/msm_shared/usb30_dwc.h b/platform/msm_shared/usb30_dwc.h
index 14402e7..5b5fc70 100644
--- a/platform/msm_shared/usb30_dwc.h
+++ b/platform/msm_shared/usb30_dwc.h
@@ -410,6 +410,8 @@
 	/* callback into client to process the setup msgs. */
 	void *setup_context;
 	int (*setup_handler)(void* context, uint8_t* data);
+	bool is_test_mode;
+	uint16_t test_mode;
 
 } dwc_dev_t;
 
diff --git a/platform/msm_shared/usb30_dwc_hw.c b/platform/msm_shared/usb30_dwc_hw.c
index 7b69bbb..2ca1a54 100644
--- a/platform/msm_shared/usb30_dwc_hw.c
+++ b/platform/msm_shared/usb30_dwc_hw.c
@@ -383,6 +383,45 @@
 	return REG_READ_FIELD(dev, DCTL, RUN_STOP);
 }
 
+void dwc_device_enter_test_mode(dwc_dev_t *dev)
+{
+	REG_WRITE_FIELD(dev, DCTL, TSTCTL, dev->test_mode);
+}
+
+void dwc_device_enable_u1(dwc_dev_t *dev, uint8_t val)
+{
+	REG_WRITE_FIELD(dev, DCTL, INITU1ENA, val);
+}
+
+void dwc_device_enable_u2(dwc_dev_t *dev, uint8_t val)
+{
+	REG_WRITE_FIELD(dev, DCTL, INITU2ENA, val);
+}
+
+void dwc_device_accept_u1u2(dwc_dev_t *dev)
+{
+	REG_WRITE_FIELD(dev, DCTL, ACCEPTU1ENA, 1);
+	REG_WRITE_FIELD(dev, DCTL, ACCEPTU2ENA, 1);
+}
+
+bool dwc_device_u1_enabled(dwc_dev_t *dev)
+{
+	uint32_t val;
+
+	val = REG_READ(dev, DCTL);
+
+	return val & (1 << 10) ? true : false;
+}
+
+bool dwc_device_u2_enabled(dwc_dev_t *dev)
+{
+	uint32_t val;
+
+	val = REG_READ(dev, DCTL);
+
+	return val & (1 << 12) ? true : false;
+}
+
 /******************** Managing various events *********************************/
 /* event init:
    program event buffer address, size and reset event count to 0.
diff --git a/platform/msm_shared/usb30_dwc_hw.h b/platform/msm_shared/usb30_dwc_hw.h
index 56b32ba..119bf20 100644
--- a/platform/msm_shared/usb30_dwc_hw.h
+++ b/platform/msm_shared/usb30_dwc_hw.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, 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
@@ -51,4 +51,10 @@
 uint8_t dwc_device_run_status(dwc_dev_t *dev);
 void dwc_gctl_init(dwc_dev_t *dev);
 void dwc_axi_master_config(dwc_dev_t *dev);
+void dwc_device_enter_test_mode(dwc_dev_t *dev);
+void dwc_device_enable_u1(dwc_dev_t *dev, uint8_t val);
+void dwc_device_enable_u2(dwc_dev_t *dev, uint8_t val);
+void dwc_device_accept_u1u2(dwc_dev_t *dev);
+bool dwc_device_u1_enabled(dwc_dev_t *dev);
+bool dwc_device_u2_enabled(dwc_dev_t *dev);
 #endif
diff --git a/platform/msm_shared/usb30_udc.c b/platform/msm_shared/usb30_udc.c
index d9d18a2..49d47d1 100644
--- a/platform/msm_shared/usb30_udc.c
+++ b/platform/msm_shared/usb30_udc.c
@@ -47,6 +47,7 @@
 #include <board.h>
 #include <platform/timer.h>
 #include <qmp_phy.h>
+#include <usb30_dwc_hw.h>
 
 //#define DEBUG_USB
 
@@ -90,14 +91,17 @@
 static void udc_register_bos_desc(udc_t *udc);
 static void udc_register_device_desc_usb_20(udc_t *udc, struct udc_device *dev_info);
 static void udc_register_device_desc_usb_30(udc_t *udc, struct udc_device *dev_info);
-static void udc_register_config_desc_usb20(udc_t *udc, struct udc_gadget *gadget);
+static void udc_register_config_desc_usb20(udc_t *udc, struct udc_gadget *gadget, uint8_t type);
 static void udc_register_config_desc_usb30(udc_t *udc, struct udc_gadget *gadget);
 
-static void udc_ept_desc_fill(struct udc_endpoint *ept, uint8_t *data);
+static void udc_ept_desc_fill(struct udc_endpoint *ept, uint8_t *data, uint8_t type);
 static void udc_ept_comp_desc_fill(struct udc_endpoint *ept, uint8_t *data);
 
 static void udc_dwc_notify(void *context, dwc_notify_event_t event);
 static int udc_handle_setup(void *context, uint8_t *data);
+static bool stall_ep;
+static bool udc_other_speed_cfg;
+static bool udc_ss_capable;
 
 /* TODO: This must be the only global var in this file, for now.
  * Ideally, all APIs should be sending
@@ -341,7 +345,7 @@
 	}
 
 	/* create our configuration descriptors based on this gadget data */
-	udc_register_config_desc_usb20(udc_dev, gadget);
+	udc_register_config_desc_usb20(udc_dev, gadget, TYPE_CONFIGURATION);
 	udc_register_config_desc_usb30(udc_dev, gadget);
 
 	/* save the gadget */
@@ -434,18 +438,28 @@
 
 	switch (SETUP(s.type, s.request))
 	{
+	case SETUP(ENDPOINT_READ, GET_STATUS):
+	case SETUP(INTERFACE_READ, GET_STATUS):
 	case SETUP(DEVICE_READ, GET_STATUS):
 		{
-			DBG("\n DEVICE_READ : GET_STATUS: value = %d index = %d"
-				" length = %d", s.value, s.index, s.length);
-
 			if (s.length == 2) {
 
-				uint16_t zero = 0;
+				uint16_t status = 0;
+				if (s.type == DEVICE_READ || (s.type == ENDPOINT_READ && stall_ep == true))
+					status = 1; /* Self-powered is set for device read and Halt bit set for end point read */
+
 				len = 2;
 
+				if (udc->usb_state == UDC_CONFIGURED_STATE && udc->speed == UDC_SPEED_SS)
+				{
+					if (s.type == DEVICE_READ && dwc_device_u1_enabled(dwc))
+						status |= (1 << 2); /* Set D2 to indicate U1 is enabled */
+					if (s.type == DEVICE_READ && dwc_device_u2_enabled(dwc))
+						status |= (1 << 3); /* Set D3 to indicate U3 is enabled */
+				}
+
 				/* copy to tx buffer */
-				memcpy(udc->ctrl_tx_buf, &zero, len);
+				memcpy(udc->ctrl_tx_buf, &status, len);
 
 				/* flush buffer to main memory before queueing the request */
 				arch_clean_invalidate_cache_range((addr_t) udc->ctrl_tx_buf, len);
@@ -464,10 +478,53 @@
 		break;
 	case SETUP(DEVICE_READ, GET_DESCRIPTOR):
 		{
-			DBG("\n DEVICE_READ : GET_DESCRIPTOR: value = %d", s.value);
+			DBG("\n DEVICE_READ : GET_DESCRIPTOR: value = %x\n", s.value);
 
 			/* setup usb ep0-IN to send our device descriptor */
 			struct udc_descriptor *desc;
+			/* Device Qualifier */
+			if (((s.value >> 8) == TYPE_DEVICE_QUALIFIER) && (udc->speed != UDC_SPEED_SS))
+			{
+				struct usb_qualifier_desc qual = {0};
+				qual.bLength = sizeof(qual);
+				qual.bDescriptorType = TYPE_DEVICE_QUALIFIER;
+				qual.bcdUSB = 0x0200; /* USB2.0 version */
+				qual.bDeviceClass = udc_dev->gadget->ifc_class;
+				qual.bDeviceSubClass = udc_dev->gadget->ifc_subclass;
+				qual.bDeviceProtocol = udc_dev->gadget->ifc_protocol;
+				qual.bMaxPacketSize0 = (udc_dev->speed == UDC_SPEED_HS) ? 64 : 512;
+				qual.bNumConfigurations = 1;
+				qual.bReserved          = 0;
+
+				if (sizeof(qual) > s.length)
+					len = s.length;
+				else
+					len = sizeof(qual);
+
+				/* copy to tx buffer */
+				memcpy(udc->ctrl_tx_buf, (void *)&qual, len);
+
+				/* flush buffer to main memory before queueing the request */
+				arch_clean_invalidate_cache_range((addr_t) udc->ctrl_tx_buf, len);
+
+				dwc_transfer_request(udc->dwc,
+									 0,
+									 DWC_EP_DIRECTION_IN,
+									 udc->ctrl_tx_buf,
+									 len,
+									 NULL,
+									 NULL);
+
+				return DWC_SETUP_3_STAGE;
+			}
+			if (((s.value >> 8) == TYPE_OTHER_SPEED_CONFIG) && (udc->speed != UDC_SPEED_SS)) /* Other speed config */
+			{
+				if (!udc_other_speed_cfg)
+				{
+					udc_register_config_desc_usb20(udc, udc->gadget, TYPE_OTHER_SPEED_CONFIG);
+					udc_other_speed_cfg = true;
+				}
+			}
 
 			for (desc = udc->desc_list; desc; desc = desc->next)
 			{
@@ -540,7 +597,10 @@
 			DBG("\n DEVICE_WRITE : SET_CONFIGURATION");
 
 			/* select configuration 1 */
-			if (s.value == 1) {
+			/* Return the config if configuration value is not 0 and move the state to
+			 * configured state
+			 */
+			if (s.value) {
 				struct udc_endpoint *ept;
 				/* enable endpoints */
 				for (ept = udc->ept_list; ept; ept = ept->next) {
@@ -562,7 +622,7 @@
 						ep->type          = ept->type;
 						ep->max_pkt_size  = ept->maxpkt;
 						ep->burst_size    = ept->maxburst;
-						ep->zlp           = 0;             /* TODO: zlp could be made part of ept */
+						ep->zlp           = 0;
 						ep->trb_count     = ept->trb_count;
 						ep->trb           = ept->trb;
 
@@ -575,12 +635,14 @@
 
 				/* now that we have saved the non-control EP details, set config */
 				dwc_device_set_configuration(dwc);
+				if (udc->speed == UDC_SPEED_SS)
+					dwc_device_accept_u1u2(dwc);
 
 				/* inform client that we are configured. */
 				udc->gadget->notify(udc_dev->gadget, UDC_EVENT_ONLINE);
 
 				udc->config_selected = 1;
-
+				udc->usb_state = UDC_CONFIGURED_STATE;
 				return DWC_SETUP_2_STAGE;
 			}
 			else if (s.value == 0)
@@ -588,13 +650,9 @@
 				/* 0 == de-configure. */
 				udc->config_selected = 0;
 				DBG("\n\n CONFIG = 0 !!!!!!!!!\n\n");
+				/* If config value is '0' change the state to addressed state */
+				udc->usb_state = UDC_ADDRESSED_STATE;
 				return DWC_SETUP_2_STAGE;
-				/* TODO: do proper handling for de-config */
-			}
-			else
-			{
-				ERR("\n CONFIG = %d not supported\n", s.value);
-				ASSERT(0);
 			}
 		}
 		break;
@@ -603,26 +661,107 @@
 			DBG("\n DEVICE_WRITE : SET_ADDRESS");
 
 			dwc_device_set_addr(dwc, s.value);
+			udc->usb_state = UDC_ADDRESSED_STATE;
 			return DWC_SETUP_2_STAGE;
 		}
 		break;
 	case SETUP(INTERFACE_WRITE, SET_INTERFACE):
 		{
-			DBG("\n DEVICE_WRITE : SET_INTERFACE");
+			DBG("\n INTERFACE_WRITE : SET_INTERFACE");
 			/* if we ack this everything hangs */
 			/* per spec, STALL is valid if there is not alt func */
 			goto stall;
 		}
 		break;
+	case SETUP(INTERFACE_WRITE, SET_FEATURE):
+		{
+			DBG("\n INTERFACE_WRITE : SET_FEATURE");
+			if (s.value == FUNCTION_SUSPEND && udc->speed == UDC_SPEED_SS)
+				return DWC_SETUP_2_STAGE;
+		}
+		break;
+	case SETUP(INTERFACE_READ, GET_INTERFACE):
+		{
+			DBG("\n INTERFACE_READ : GET_INTERFACE");
+			/* per spec, STALL is valid if there is not alt func */
+			goto stall;
+		}
+		break;
+	case SETUP(ENDPOINT_WRITE, SET_FEATURE):
+		{
+			DBG("\n ENDPOINT_WRITE : SET_FEATURE");
+			if (s.value == ENDPOINT_HALT)
+			{
+				uint8_t usb_epnum;
+				uint8_t dir;
+
+				usb_epnum = (s.index & USB_EP_NUM_MASK);
+				dir = ((s.index & USB_EP_DIR_MASK) == USB_EP_DIR_IN) ? 0x1 : 0x0;
+				dwc_ep_cmd_stall(dwc, DWC_EP_PHY_NUM(usb_epnum, dir));
+				stall_ep = true;
+				return DWC_SETUP_2_STAGE;
+			}
+			else
+				goto stall;
+		}
 	case SETUP(DEVICE_WRITE, SET_FEATURE):
 		{
 			DBG("\n DEVICE_WRITE : SET_FEATURE");
+
+			if (s.value == TEST_MODE)
+			{
+				dwc->test_mode = s.index;
+
+				switch(dwc->test_mode)
+				{
+				case TEST_J:
+				case TEST_K:
+				case TEST_SE0_NAK:
+				case TEST_PACKET:
+				case TEST_FORCE_ENABLE:
+					/* Upper byte of Windex contain test mode */
+					dwc->test_mode >>= 8;
+					dwc->is_test_mode = true;
+					break;
+				default:
+					DBG("\n Unknown test mode: %x\n", dwc->test_mode);
+				}
+				return DWC_SETUP_2_STAGE;
+			}
+			if (udc->usb_state == UDC_CONFIGURED_STATE && udc->speed == UDC_SPEED_SS)
+			{
+				/* Set U1 & U2 only in configured state */
+				if (s.value == U1_ENABLE)
+				{
+					dwc_device_enable_u1(dwc, 1);
+					return DWC_SETUP_2_STAGE;
+				}
+				if (s.value == U2_ENABLE)
+				{
+					dwc_device_enable_u2(dwc, 1);
+					return DWC_SETUP_2_STAGE;
+				}
+			}
 			goto stall;
 		}
 		break;
 	case SETUP(DEVICE_WRITE, CLEAR_FEATURE):
 		{
 			DBG("\n DEVICE_WRITE : CLEAR_FEATURE");
+			/* Clear U1 & U2 only in configured state */
+			if (udc->usb_state == UDC_CONFIGURED_STATE && udc->speed == UDC_SPEED_SS)
+			{
+				if (s.value == U1_ENABLE)
+				{
+					dwc_device_enable_u1(dwc, 0);
+					return DWC_SETUP_2_STAGE;
+				}
+				if (s.value == U2_ENABLE)
+				{
+					dwc_device_enable_u2(dwc, 0);
+					return DWC_SETUP_2_STAGE;
+				}
+			}
 			goto stall;
 		}
 		break;
@@ -660,6 +799,7 @@
 			 * physical ep 31 --> logical ep 15 IN
 			 */
 			dwc_ep_cmd_clear_stall(dwc, DWC_EP_PHY_NUM(usb_epnum, dir));
+			stall_ep = false;
 
 			return DWC_SETUP_2_STAGE;
 		}
@@ -686,7 +826,12 @@
 			}
 		}
 		break;
-
+	case SETUP(DEVICE_WRITE, SET_ISOCH_DELAY):
+		{
+			DBG("\n DEVICE_WRITE: SET_ISOCH_DELAY\n");
+			return DWC_SETUP_2_STAGE;
+		}
+		break;
 	default:
 		/* some of the requests from host are not handled, add a debug
 		 * for the command not being handled, this is not fatal
@@ -764,6 +909,23 @@
 	return ret;
 }
 
+/* For HS device should have the version number as 0x0200.
+ * Update the minor version to 0x00 when we receive the connect
+ * event with HS or FS mode
+ */
+static void udc_update_usb20_desc(udc_t *udc)
+{
+	struct udc_descriptor *desc= NULL;
+	if (udc_ss_capable)
+		return;
+
+	for (desc = udc->desc_list; desc; desc = desc->next)
+	{
+		if (desc->spec == UDC_DESC_SPEC_20 && desc->data[1] == TYPE_DEVICE)
+			desc->data[2] = 0x00; /* usb spec minor rev */
+	}
+}
+
 static void udc_update_ep_desc(udc_t *udc, uint16_t max_pkt_sz_bulk)
 {
 	struct udc_descriptor *desc= NULL;
@@ -815,6 +977,8 @@
 		 */
 		max_pkt_size = 64;
 		udc_update_ep_desc(udc, max_pkt_size);
+		/* Update the spec version for FS */
+		udc_update_usb20_desc(udc);
 		break;
 	case DWC_NOTIFY_EVENT_CONNECTED_HS:
 		udc->speed = UDC_SPEED_HS;
@@ -823,6 +987,8 @@
 		 */
 		max_pkt_size = 512;
 		udc_update_ep_desc(udc, max_pkt_size);
+		/* Update the spec version for HS */
+		udc_update_usb20_desc(udc);
 		break;
 	case DWC_NOTIFY_EVENT_CONNECTED_SS:
 		udc->speed = UDC_SPEED_SS;
@@ -830,6 +996,7 @@
 		 * with SS max packet size
 		 */
 		max_pkt_size = 1024;
+		udc_ss_capable = true;
 		udc_update_ep_desc(udc, max_pkt_size);
 		break;
 	case DWC_NOTIFY_EVENT_DISCONNECTED:
@@ -912,7 +1079,7 @@
 
 /* create config + interface + ep desc for 2.0 */
 static void udc_register_config_desc_usb20(udc_t *udc,
-										   struct udc_gadget *gadget)
+										   struct udc_gadget *gadget, uint8_t type)
 {
 	uint8_t  *data;
 	uint16_t  size;
@@ -928,13 +1095,13 @@
 		   UDC_DESC_SIZE_INTERFACE +
 		   (gadget->ifc_endpoints*UDC_DESC_SIZE_ENDPOINT);
 
-	desc = udc_descriptor_alloc(TYPE_CONFIGURATION, 0, size, UDC_DESC_SPEC_20);
+	desc = udc_descriptor_alloc(type, 0, size, UDC_DESC_SPEC_20);
 
 	data = desc->data;
 
 	/* Config desc */
 	data[0] = 0x09;
-	data[1] = TYPE_CONFIGURATION;
+	data[1] = type;
 	data[2] = size;
 	data[3] = size >> 8;
 	data[4] = 0x01;     /* number of interfaces */
@@ -957,7 +1124,7 @@
 	data += 9;
 
 	for (uint8_t n = 0; n < gadget->ifc_endpoints; n++) {
-		udc_ept_desc_fill(gadget->ept[n], data);
+		udc_ept_desc_fill(gadget->ept[n], data, type);
 		data += UDC_DESC_SIZE_ENDPOINT;
 	}
 
@@ -1013,7 +1180,7 @@
 	for (uint8_t n = 0; n < gadget->ifc_endpoints; n++)
 	{
 		/* fill EP desc */
-		udc_ept_desc_fill(gadget->ept[n], data);
+		udc_ept_desc_fill(gadget->ept[n], data, 0);
 		data += UDC_DESC_SIZE_ENDPOINT;
 
 		/* fill EP companion desc */
@@ -1038,7 +1205,7 @@
 	/* data 0 and 1 is filled by descriptor alloc routine.
 	 * fill in the remaining entries.
 	 */
-	data[2] = 0x00; /* usb spec minor rev */
+	data[2] = 0x10; /* usb spec minor rev */
 	data[3] = 0x02; /* usb spec major rev */
 	data[4] = 0x00; /* class */
 	data[5] = 0x00; /* subclass */
@@ -1092,7 +1259,7 @@
 	struct udc_descriptor *desc;
 
 	/* create our device descriptor */
-	desc = udc_descriptor_alloc(TYPE_BOS, 0, 15, UDC_DESC_SPEC_30); /* 15 is total length of bos + other descriptors inside it */
+	desc = udc_descriptor_alloc(TYPE_BOS, 0, 0x16, UDC_DESC_SPEC_30); /* 22 is total length of bos + other descriptors inside it */
 	data = desc->data;
 
 	/* data 0 and 1 is filled by descriptor alloc routine.
@@ -1100,20 +1267,30 @@
 	 */
 	data[0] = 0x05;     /* BOS desc len */
 	data[1] = TYPE_BOS; /* BOS desc type */
-	data[2] = 0x0F;     /* total len of bos desc and its sub desc */
+	data[2] = 0x16;     /* total len of bos desc and its sub desc */
 	data[3] = 0x00;     /* total len of bos desc and its sub desc */
-	data[4] = 0x01;     /* num of sub desc inside bos */
+	data[4] = 0x02;     /* num of sub desc inside bos */
 
-	data[5]  = 0x0A;    /* desc len */
-	data[6]  = 0x10;    /* Device Capability desc */
-	data[7]  = 0x03;    /* 3 == SuperSpeed capable */
-	data[8]  = 0x00;    /* Attribute: latency tolerance msg: No */
-	data[9]  = 0x0F;    /* Supported Speeds (bit mask): LS, FS, HS, SS */
-	data[10] = 0x00;    /* Reserved part of supported wSupportedSpeeds */
-	data[11] = 0x01;    /* lowest supported speed with full functionality: FS */
-	data[12] = 0x00;    /* U1 device exit latency */
-	data[13] = 0x00;    /* U2 device exit latency (lsb) */
-	data[14] = 0x00;    /* U2 device exit latency (msb) */
+	/* USB2.0 extension Descriptor */
+	data[5]  = 0x07;    /* Size of USB2.0 extension desc */
+	data[6]  = 0x10;    /* Device capability desc */
+	data[7]  = 0x02;    /* USB2.0 extension descriptor */
+	data[8]  = 0x02;    /* LPM mode */
+	data[9]  = 0x00;    /* Reserved */
+	data[10] = 0x00;    /* Reserved */
+	data[11] = 0x00;    /* Reserved */
+
+	/* Super Speed device capability */
+	data[12]  = 0x0A;    /* desc len */
+	data[13]  = 0x10;    /* Device Capability desc */
+	data[14]  = 0x03;    /* 3 == SuperSpeed capable */
+	data[15]  = 0x00;    /* Attribute: latency tolerance msg: No */
+	data[16]  = 0x0F;    /* Supported Speeds (bit mask): LS, FS, HS, SS */
+	data[17] = 0x00;    /* Reserved part of supported wSupportedSpeeds */
+	data[18] = 0x01;    /* lowest supported speed with full functionality: FS */
+	data[19] = 0x00;    /* U1 device exit latency */
+	data[20] = 0x00;    /* U2 device exit latency (lsb) */
+	data[21] = 0x00;    /* U2 device exit latency (msb) */
 
 	udc_descriptor_register(udc, desc);
 }
@@ -1131,14 +1308,25 @@
 	udc_descriptor_register(udc, desc);
 }
 
-static void udc_ept_desc_fill(struct udc_endpoint *ept, uint8_t *data)
+static void udc_ept_desc_fill(struct udc_endpoint *ept, uint8_t *data, uint8_t type)
 {
+	uint16_t max_pkt_sz = 0;
+
+	/* For other speed configuration, populate the max packet size for the other speed
+	 * mode. For eg: if currently host is operating in HS mode, return the configuration
+	 * for FS mode
+	 */
+	if (type == TYPE_OTHER_SPEED_CONFIG && udc_dev->speed != UDC_SPEED_SS)
+		max_pkt_sz = (udc_dev->speed == UDC_SPEED_FS) ? 512 : 64;
+	else
+		max_pkt_sz = ept->maxpkt;
+
 	data[0] = 7;
 	data[1] = TYPE_ENDPOINT;
 	data[2] = ept->num | (ept->in ? 0x80 : 0x00);
 	data[3] = 0x02; /* bulk -- the only kind we support */
-	data[4] = ept->maxpkt;
-	data[5] = ept->maxpkt >> 8;
+	data[4] = max_pkt_sz;
+	data[5] = max_pkt_sz >> 8;
 	data[6] = 0; /* bInterval: must be 0 for bulk. */
 }
 
diff --git a/platform/msm_shared/usb30_udc.h b/platform/msm_shared/usb30_udc.h
index 97ef7e8..56a2b10 100644
--- a/platform/msm_shared/usb30_udc.h
+++ b/platform/msm_shared/usb30_udc.h
@@ -39,6 +39,22 @@
 
 typedef enum
 {
+	UDC_DEFAULT_STATE,
+	UDC_ADDRESSED_STATE,
+	UDC_CONFIGURED_STATE,
+} usb_state_t;
+
+typedef enum
+{
+	ENDPOINT_HALT = 0,
+	FUNCTION_SUSPEND = 0,
+	U1_ENABLE = 48,
+	U2_ENABLE = 49,
+	LTM_ENABLE = 50,
+} udc_feature_select_t;
+
+typedef enum
+{
 	UDC_DESC_SPEC_20 = BIT(0),
 	UDC_DESC_SPEC_30 = BIT(1),
 } udc_desc_spec_t;
@@ -69,6 +85,7 @@
 	uint8_t                config_selected; /* keeps track of the selected configuration */
 
 	struct udc_request    *queued_req;      /* pointer to the currently queued request. NULL indicates no request is queued. */
+	usb_state_t            usb_state;       /* USB state, default, addressed & configured */
 
 } udc_t;
 
@@ -93,6 +110,18 @@
 	uint32_t             trb_count; /* size of TRB chain. */
 };
 
+struct usb_qualifier_desc {
+	uint8_t bLength;
+	uint8_t bDescriptorType;
+	uint16_t bcdUSB;
+	uint8_t bDeviceClass;
+	uint8_t bDeviceSubClass;
+	uint8_t bDeviceProtocol;
+	uint8_t bMaxPacketSize0;
+	uint8_t bNumConfigurations;
+	uint8_t bReserved;
+}__PACKED;
+
 struct udc_request *usb30_udc_request_alloc(void);
 struct udc_endpoint *usb30_udc_endpoint_alloc(unsigned type, unsigned maxpkt);
 void usb30_udc_request_free(struct udc_request *req);
diff --git a/project/msm8996.mk b/project/msm8996.mk
index 1eaf598..eecf740 100644
--- a/project/msm8996.mk
+++ b/project/msm8996.mk
@@ -5,6 +5,7 @@
 TARGET := msm8996
 
 MODULES += app/aboot
+MODULES += app/mmutest
 
 ifeq ($(TARGET_BUILD_VARIANT),user)
 DEBUG := 0
@@ -22,6 +23,7 @@
 ENABLE_RPMB_SUPPORT := 1
 ENABLE_GLINK_SUPPORT := 1
 ENABLE_PWM_SUPPORT := true
+ENABLE_LPAE_SUPPORT := 1
 
 DEFINES +=VIRTIO=1
 
@@ -80,6 +82,10 @@
 DEFINES += WDOG_SUPPORT=1
 endif
 
+ifeq ($(ENABLE_LPAE_SUPPORT),1)
+DEFINES += LPAE=1
+endif
+
 CFLAGS += -Werror
 
 #SCM call before entering DLOAD mode
diff --git a/target/msm8952/oem_panel.c b/target/msm8952/oem_panel.c
index 09b767b..b64ac32 100644
--- a/target/msm8952/oem_panel.c
+++ b/target/msm8952/oem_panel.c
@@ -81,7 +81,7 @@
 
 static uint32_t panel_id;
 
-#define TRULY_1080P_CMD_PANEL_ON_DELAY 40
+#define TRULY_1080P_PANEL_ON_DELAY 40
 
 int oem_panel_rotation()
 {
@@ -97,8 +97,9 @@
 	if (panel_id == OTM1906C_1080P_CMD_PANEL) {
 		/* needs extra delay to avoid unexpected artifacts */
 		mdelay(OTM1906C_1080P_CMD_PANEL_ON_DELAY);
-	} else if (panel_id == TRULY_1080P_CMD_PANEL) {
-		mdelay(TRULY_1080P_CMD_PANEL_ON_DELAY);
+	} else if (panel_id == TRULY_1080P_CMD_PANEL ||
+			panel_id == TRULY_1080P_VIDEO_PANEL) {
+		mdelay(TRULY_1080P_PANEL_ON_DELAY);
 	}
 
 	return NO_ERROR;
diff --git a/target/msm8996/init.c b/target/msm8996/init.c
index 0042a7e..f407eea 100644
--- a/target/msm8996/init.c
+++ b/target/msm8996/init.c
@@ -136,8 +136,6 @@
 	if (platform_boot_dev_isemmc())
 	{
 		mmc_put_card_to_sleep(dev);
-		/* Disable HC mode before jumping to kernel */
-		sdhci_mode_disable(&dev->host);
 	}
 
 	if (is_sec_app_loaded())
diff --git a/target/msm8996/rules.mk b/target/msm8996/rules.mk
index 3eb7f9e..57e3c4a 100644
--- a/target/msm8996/rules.mk
+++ b/target/msm8996/rules.mk
@@ -6,14 +6,18 @@
 PLATFORM := msm8996
 
 MEMBASE := 0x90B00000 # SDRAM
-MEMSIZE := 0x00300000 # 3MB
+MEMSIZE := 0x00400000 # 4MB
 
 BASE_ADDR    := 0x0000000
 
-SCRATCH_ADDR := 0x90E00000
-SCRATCH_SIZE := 512
+SCRATCH_ADDR := 0x91100000
+SCRATCH_SIZE := 750
 KERNEL_ADDR  := 0x80000000
-KERNEL_SIZE  := 62
+KERNEL_SIZE  := 88
+# LPAE supports only 32 virtual address, L1 pt size is 4
+L1_PT_SZ     := 4
+L2_PT_SZ     := 2
+
 
 DEFINES += DISPLAY_SPLASH_SCREEN=1
 DEFINES += DISPLAY_TYPE_MIPI=1
@@ -37,7 +41,9 @@
 	KERNEL_SIZE=$(KERNEL_SIZE) \
 	RAMDISK_ADDR=$(RAMDISK_ADDR) \
 	SCRATCH_ADDR=$(SCRATCH_ADDR) \
-	SCRATCH_SIZE=$(SCRATCH_SIZE)
+	SCRATCH_SIZE=$(SCRATCH_SIZE) \
+	L1_PT_SZ=$(L1_PT_SZ) \
+	L2_PT_SZ=$(L2_PT_SZ)
 
 
 OBJS += \