Merge "msm_shared: mdp: Add support to setup each layer mixer"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 7c7f78b..86cbadc 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -591,7 +591,7 @@
 
 #if DEVICE_TREE
 	struct dt_table *table;
-	struct dt_entry *dt_entry_ptr;
+	struct dt_entry dt_entry;
 	unsigned dt_table_offset;
 	uint32_t dt_actual;
 #endif
@@ -735,29 +735,24 @@
 
 			memmove((void *) dt_buf, (char *)dt_table_offset, page_size);
 
-			/* Restriction that the device tree entry table should be less than a page*/
-			ASSERT(((table->num_entries * sizeof(struct dt_entry))+ DEV_TREE_HEADER_SIZE) < hdr->page_size);
-
-			/* Validate the device tree table header */
-			if((table->magic != DEV_TREE_MAGIC) && (table->version != DEV_TREE_VERSION)) {
+			if (dev_tree_validate(table, hdr->page_size) != 0) {
 				dprintf(CRITICAL, "ERROR: Cannot validate Device Tree Table \n");
 				return -1;
 			}
-
 			/* Find index of device tree within device tree table */
-			if((dt_entry_ptr = dev_tree_get_entry_ptr(table)) == NULL){
+			if(dev_tree_get_entry_info(table, &dt_entry) != 0){
 				dprintf(CRITICAL, "ERROR: Device Tree Blob cannot be found\n");
 				return -1;
 			}
 
 			/* Validate and Read device device tree in the "tags_add */
-			if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry_ptr->size))
+			if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size))
 			{
 				dprintf(CRITICAL, "Device tree addresses overlap with aboot addresses.\n");
 				return -1;
 			}
 
-			memmove((void *)hdr->tags_addr, (char *)dt_table_offset + dt_entry_ptr->offset, dt_entry_ptr->size);
+			memmove((void *)hdr->tags_addr, (char *)dt_table_offset + dt_entry.offset, dt_entry.size);
 		} else {
 			/*
 			 * If appended dev tree is found, update the atags with
@@ -820,30 +815,26 @@
 			}
 			table = (struct dt_table*) dt_buf;
 
-			/* Restriction that the device tree entry table should be less than a page*/
-			ASSERT(((table->num_entries * sizeof(struct dt_entry))+ DEV_TREE_HEADER_SIZE) < hdr->page_size);
-
-			/* Validate the device tree table header */
-			if((table->magic != DEV_TREE_MAGIC) && (table->version != DEV_TREE_VERSION)) {
+			if (dev_tree_validate(table, hdr->page_size) != 0) {
 				dprintf(CRITICAL, "ERROR: Cannot validate Device Tree Table \n");
 				return -1;
 			}
 
-			/* Calculate the offset of device tree within device tree table */
-			if((dt_entry_ptr = dev_tree_get_entry_ptr(table)) == NULL){
+			/* Find index of device tree within device tree table */
+			if(dev_tree_get_entry_info(table, &dt_entry) != 0){
 				dprintf(CRITICAL, "ERROR: Getting device tree address failed\n");
 				return -1;
 			}
 
 			/* Validate and Read device device tree in the "tags_add */
-			if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry_ptr->size))
+			if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size))
 			{
 				dprintf(CRITICAL, "Device tree addresses overlap with aboot addresses.\n");
 				return -1;
 			}
 
-			if(mmc_read(ptn + offset + dt_entry_ptr->offset,
-						 (void *)hdr->tags_addr, dt_entry_ptr->size)) {
+			if(mmc_read(ptn + offset + dt_entry.offset,
+						 (void *)hdr->tags_addr, dt_entry.size)) {
 				dprintf(CRITICAL, "ERROR: Cannot read device tree\n");
 				return -1;
 			}
@@ -894,7 +885,7 @@
 
 #if DEVICE_TREE
 	struct dt_table *table;
-	struct dt_entry *dt_entry_ptr;
+	struct dt_entry dt_entry;
 	uint32_t dt_actual;
 #endif
 
@@ -1024,7 +1015,7 @@
 		memmove((void*) hdr->ramdisk_addr, (char *)(image_addr + page_size + kernel_actual), hdr->ramdisk_size);
 #if DEVICE_TREE
 		/* Validate and Read device device tree in the "tags_add */
-		if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry_ptr->size))
+		if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size))
 		{
 			dprintf(CRITICAL, "Device tree addresses overlap with aboot addresses.\n");
 			return -1;
@@ -1087,31 +1078,27 @@
 
 			table = (struct dt_table*) dt_buf;
 
-			/* Restriction that the device tree entry table should be less than a page*/
-			ASSERT(((table->num_entries * sizeof(struct dt_entry))+ DEV_TREE_HEADER_SIZE) < hdr->page_size);
-
-			/* Validate the device tree table header */
-			if((table->magic != DEV_TREE_MAGIC) && (table->version != DEV_TREE_VERSION)) {
+			if (dev_tree_validate(table, hdr->page_size) != 0) {
 				dprintf(CRITICAL, "ERROR: Cannot validate Device Tree Table \n");
 				return -1;
 			}
 
-			/* Calculate the offset of device tree within device tree table */
-			if((dt_entry_ptr = dev_tree_get_entry_ptr(table)) == NULL){
+			/* Find index of device tree within device tree table */
+			if(dev_tree_get_entry_info(table, &dt_entry) != 0){
 				dprintf(CRITICAL, "ERROR: Getting device tree address failed\n");
 				return -1;
 			}
 
 			/* Validate and Read device device tree in the "tags_add */
-			if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry_ptr->size))
+			if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size))
 			{
 				dprintf(CRITICAL, "Device tree addresses overlap with aboot addresses.\n");
 				return -1;
 			}
 
 			/* Read device device tree in the "tags_add */
-			if(flash_read(ptn, offset + dt_entry_ptr->offset,
-						 (void *)hdr->tags_addr, dt_entry_ptr->size)) {
+			if(flash_read(ptn, offset + dt_entry.offset,
+						 (void *)hdr->tags_addr, dt_entry.size)) {
 				dprintf(CRITICAL, "ERROR: Cannot read device tree\n");
 				return -1;
 			}
@@ -1298,7 +1285,7 @@
 	uint32 dt_image_offset = 0;
 	uint32_t n;
 	struct dt_table *table;
-	struct dt_entry *dt_entry_ptr;
+	struct dt_entry dt_entry;
 
 	struct boot_img_hdr *hdr = (struct boot_img_hdr *) (boot_image_start);
 
@@ -1322,23 +1309,18 @@
 		/* offset now point to start of dt.img */
 		table = (struct dt_table*)(boot_image_start + dt_image_offset);
 
-		/* Restriction that the device tree entry table should be less than a page*/
-		ASSERT(((table->num_entries * sizeof(struct dt_entry))+ DEV_TREE_HEADER_SIZE) < hdr->page_size);
-
-		/* Validate the device tree table header */
-		if((table->magic != DEV_TREE_MAGIC) && (table->version != DEV_TREE_VERSION)) {
+		if (dev_tree_validate(table, hdr->page_size) != 0) {
 			dprintf(CRITICAL, "ERROR: Cannot validate Device Tree Table \n");
 			return -1;
 		}
-
-		/* Calculate the offset of device tree within device tree table */
-		if((dt_entry_ptr = dev_tree_get_entry_ptr(table)) == NULL){
+		/* Find index of device tree within device tree table */
+		if(dev_tree_get_entry_info(table, &dt_entry) != 0){
 			dprintf(CRITICAL, "ERROR: Getting device tree address failed\n");
 			return -1;
 		}
 
 		/* Validate and Read device device tree in the "tags_add */
-		if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry_ptr->size))
+		if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size))
 		{
 			dprintf(CRITICAL, "Device tree addresses overlap with aboot addresses.\n");
 			return -1;
@@ -1346,8 +1328,8 @@
 
 		/* Read device device tree in the "tags_add */
 		memmove((void*) hdr->tags_addr,
-				boot_image_start + dt_image_offset +  dt_entry_ptr->offset,
-				dt_entry_ptr->size);
+				boot_image_start + dt_image_offset +  dt_entry.offset,
+				dt_entry.size);
 	} else
 		return -1;
 
@@ -1977,15 +1959,15 @@
 	/* Check if we should do something other than booting up */
 	if (keys_get_state(KEY_VOLUMEUP) && keys_get_state(KEY_VOLUMEDOWN))
 	{
-		dprintf(ALWAYS,"dload mode key sequence detected");
-		if (set_download_mode())
+		dprintf(ALWAYS,"dload mode key sequence detected\n");
+		if (set_download_mode(EMERGENCY_DLOAD))
 		{
-			dprintf(CRITICAL,"dload mode not supported by target");
+			dprintf(CRITICAL,"dload mode not supported by target\n");
 		}
 		else
 		{
 			reboot_device(0);
-			dprintf(CRITICAL,"Failed to reboot into dload mode");
+			dprintf(CRITICAL,"Failed to reboot into dload mode\n");
 		}
 		boot_into_fastboot = true;
 	}
diff --git a/app/aboot/recovery.c b/app/aboot/recovery.c
index 8c79f28..817a6be 100644
--- a/app/aboot/recovery.c
+++ b/app/aboot/recovery.c
@@ -95,6 +95,7 @@
 	unsigned offset = 0;
 	unsigned pagesize = flash_page_size();
 	unsigned n = 0;
+	void *scratch_addr = target_get_scratch_address();
 
 	ptable = flash_get_ptable();
 
@@ -111,15 +112,15 @@
 
 	n = pagesize * (MISC_COMMAND_PAGE + 1);
 
-	if (flash_read(ptn, offset, (void *) SCRATCH_ADDR, n)) {
+	if (flash_read(ptn, offset, scratch_addr, n)) {
 		dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
 		return -1;
 	}
 
 	offset += (pagesize * MISC_COMMAND_PAGE);
-	offset += SCRATCH_ADDR;
+	offset += (unsigned) scratch_addr;
 	memcpy((void *) offset, in, sizeof(*in));
-	if (flash_write(ptn, 0, (void *)SCRATCH_ADDR, n)) {
+	if (flash_write(ptn, 0, scratch_addr, n)) {
 		dprintf(CRITICAL, "ERROR: flash write fail!\n");
 		return -1;
 	}
@@ -165,6 +166,7 @@
 	unsigned pagesize = flash_page_size();
 	unsigned pagemask = pagesize -1;
 	unsigned n = 0;
+	void *scratch_addr = target_get_scratch_address();
 
 	ptable = flash_get_ptable();
 	if (ptable == NULL) {
@@ -181,7 +183,7 @@
 	offset += header->image_offset;
 	n = (header->image_length + pagemask) & (~pagemask);
 
-	if (flash_read(ptn, offset, (void *) SCRATCH_ADDR, n)) {
+	if (flash_read(ptn, offset, scratch_addr, n)) {
 		dprintf(CRITICAL, "ERROR: Cannot read radio image\n");
 		return -1;
 	}
@@ -192,7 +194,7 @@
 		return -1;
 	}
 
-	if (flash_write(ptn, 0, (void *) SCRATCH_ADDR, n)) {
+	if (flash_write(ptn, 0, scratch_addr, n)) {
 		dprintf(CRITICAL, "ERROR: flash write fail!\n");
 		return -1;
 	}
diff --git a/dev/pmic/pm8x41/include/pm8x41.h b/dev/pmic/pm8x41/include/pm8x41.h
index 03de67d..3678bea 100644
--- a/dev/pmic/pm8x41/include/pm8x41.h
+++ b/dev/pmic/pm8x41/include/pm8x41.h
@@ -83,6 +83,101 @@
 	int disable_pin;
 };
 
+struct pm8x41_ldo {
+	uint8_t  type;
+	uint32_t base;
+};
+
+/* LDO base addresses. */
+#define PM8x41_LDO2                           0x14100
+#define PM8x41_LDO4                           0x14300
+#define PM8x41_LDO12                          0x14B00
+#define PM8x41_LDO14                          0x14D00
+#define PM8x41_LDO19                          0x15200
+#define PM8x41_LDO22                          0x15500
+
+/* LDO voltage ranges */
+#define NLDO_UV_MIN                           375000
+#define NLDO_UV_MAX                           1537500
+#define NLDO_UV_STEP                          12500
+#define NLDO_UV_VMIN_LOW                      750000
+
+#define PLDO_UV_VMIN_LOW                      750000
+#define PLDO_UV_VMIN_MID                      1500000
+#define PLDO_UV_VMIN_HIGH                     1750000
+
+#define PLDO_UV_MIN                           1537500
+#define PDLO_UV_MID                           3075000
+#define PLDO_UV_MAX                           4900000
+#define PLDO_UV_STEP_LOW                      12500
+#define PLDO_UV_STEP_MID                      25000
+#define PLDO_UV_STEP_HIGH                     50000
+
+#define LDO_RANGE_SEL_BIT                     0
+#define LDO_VSET_SEL_BIT                      0
+#define LDO_VREG_ENABLE_BIT                   7
+#define LDO_NORMAL_PWR_BIT                    7
+
+#define PLDO_TYPE                             0
+#define NLDO_TYPE                             1
+
+#define LDO(_base, _type) \
+{ \
+	.type = _type, \
+	.base = _base, \
+}
+
+enum mpp_vin_select
+{
+	MPP_VIN0,
+	MPP_VIN1,
+	MPP_VIN2,
+	MPP_VIN3,
+};
+
+enum mpp_mode_en_source_select
+{
+	MPP_LOW,
+	MPP_HIGH,
+	MPP_PAIRED_MPP,
+	MPP_NOT_PAIRED_MPP,
+	MPP_DTEST1 = 8,
+	MPP_NOT_DTEST1,
+	MPP_DTEST2,
+	MPP_NOT_DTEST2,
+	MPP_DTEST3,
+	MPP_NOT_DTEST3,
+	MPP_DTEST4,
+	MPP_NOT_DTEST4,
+};
+
+enum mpp_en_ctl
+{
+	MPP_DISABLE,
+	MPP_ENABLE,
+};
+
+enum mpp_mode
+{
+	MPP_DIGITAL_INPUT,
+	MPP_DIGITAL_OUTPUT,
+	MPP_DIGITAL_IN_AND_OUT,
+	MPP_BIDIRECTIONAL,
+	MPP_ANALOG_INPUT,
+	MPP_ANALOG_OUTPUT,
+	MPP_CURRENT_SINK,
+	MPP_RESERVED,
+};
+
+struct pm8x41_mpp
+{
+	uint32_t                       base;
+	enum mpp_vin_select            vin;
+	enum mpp_mode_en_source_select mode;
+};
+
+#define PM8x41_MMP3_BASE                      0xA200
+
 int pm8x41_gpio_get(uint8_t gpio, uint8_t *status);
 int pm8x41_gpio_set(uint8_t gpio, uint8_t value);
 int pm8x41_gpio_config(uint8_t gpio, struct pm8x41_gpio *config);
@@ -91,17 +186,11 @@
 uint32_t pm8x41_resin_bark_workaround_status();
 void pm8x41_reset_configure(uint8_t);
 void pm8x41_v2_reset_configure(uint8_t);
-int pm8x41_ldo_set_voltage(const char *, uint32_t);
-int pm8x41_ldo_control(const char *, uint8_t);
+int pm8x41_ldo_set_voltage(struct pm8x41_ldo *ldo, uint32_t voltage);
+int pm8x41_ldo_control(struct pm8x41_ldo *ldo, uint8_t enable);
 uint8_t pm8x41_get_pmic_rev();
 uint8_t pm8x41_get_pon_reason();
+void pm8x41_config_output_mpp(struct pm8x41_mpp *mpp);
+void pm8x41_enable_mpp(struct pm8x41_mpp *mpp, enum mpp_en_ctl enable);
 
-struct pm8x41_ldo {
-	const char *name;
-	uint8_t type;
-	uint32_t base;
-	uint32_t range_reg;
-	uint32_t step_reg;
-	uint32_t enable_reg;
-};
 #endif
diff --git a/dev/pmic/pm8x41/include/pm8x41_hw.h b/dev/pmic/pm8x41/include/pm8x41_hw.h
index cfc72fb..8a275ad 100644
--- a/dev/pmic/pm8x41/include/pm8x41_hw.h
+++ b/dev/pmic/pm8x41/include/pm8x41_hw.h
@@ -79,6 +79,14 @@
 #define S2_RESET_TYPE_WARM                    0x1
 #define PON_RESIN_N_RESET_S2_TIMER_MAX_VALUE  0x7
 
+/* MPP registers */
+#define MPP_DIG_VIN_CTL                       0x41
+#define MPP_MODE_CTL                          0x40
+#define MPP_EN_CTL                            0x46
+
+#define MPP_MODE_CTL_MODE_SHIFT               4
+#define MPP_EN_CTL_ENABLE_SHIFT               7
+
 void pm8x41_reg_write(uint32_t addr, uint8_t val);
 uint8_t pm8x41_reg_read(uint32_t addr);
 
@@ -90,44 +98,9 @@
 #define PERIPH_ID(_addr)    (((_addr) & 0xFF00) >> 8)
 #define SLAVE_ID(_addr)     ((_addr) >> 16)
 
-/* LDO voltage ranges */
-#define NLDO_UV_MIN                           375000
-#define NLDO_UV_MAX                           1537500
-#define NLDO_UV_STEP                          12500
-#define NLDO_UV_VMIN_LOW                      750000
-
-#define PLDO_UV_VMIN_LOW                      750000
-#define PLDO_UV_VMIN_MID                      1500000
-#define PLDO_UV_VMIN_HIGH                     1750000
-
-#define PLDO_UV_MIN                           1537500
-#define PDLO_UV_MID                           3075000
-#define PLDO_UV_MAX                           4900000
-#define PLDO_UV_STEP_LOW                      12500
-#define PLDO_UV_STEP_MID                      25000
-#define PLDO_UV_STEP_HIGH                     50000
-
-#define LDO_RANGE_SEL_BIT                     0
-#define LDO_VSET_SEL_BIT                      0
-#define LDO_VREG_ENABLE_BIT                   7
-#define LDO_NORMAL_PWR_BIT                    7
-
 #define LDO_RANGE_CTRL                        0x40
 #define LDO_STEP_CTRL                         0x41
 #define LDO_POWER_MODE                        0x45
 #define LDO_EN_CTL_REG                        0x46
 
-#define PLDO_TYPE                             0
-#define NLDO_TYPE                             1
-
-#define LDO(_name, _type, _base, _range, _step, _enable) \
-{ \
-	.name = _name, \
-	.type = _type, \
-	.base = _base, \
-	.range_reg = _range, \
-	.step_reg = _step, \
-	.enable_reg = _enable, \
-}
-
 #endif
diff --git a/dev/pmic/pm8x41/include/pm8x41_wled.h b/dev/pmic/pm8x41/include/pm8x41_wled.h
index 74c91bc..b357794 100644
--- a/dev/pmic/pm8x41/include/pm8x41_wled.h
+++ b/dev/pmic/pm8x41/include/pm8x41_wled.h
@@ -32,6 +32,7 @@
 
 #define PM_WLED_BASE                 0x1D800
 #define PM_WLED_CTNL_REG(n)          (PM_WLED_BASE + n)
+#define PM_WLED_LED_CTNL_REG(n)      (PM_WLED_BASE + 0x60 + (n-1)*10)
 
 #define PM_WLED_LED1_BRIGHTNESS_LSB  PM_WLED_CTNL_REG(0x40)
 #define PM_WLED_LED1_BRIGHTNESS_MSB  PM_WLED_CTNL_REG(0x41)
@@ -43,7 +44,9 @@
 #define PM_WLED_ILED_SYNC_BIT        PM_WLED_CTNL_REG(0x47)
 #define PM_WLED_MODULATION_SCHEME    PM_WLED_CTNL_REG(0x4A)
 #define PM_WLED_MAX_DUTY_CYCLE       PM_WLED_CTNL_REG(0x4B)
+#define PM_WLED_OVP                  PM_WLED_CTNL_REG(0x4D)
 #define PM_WLED_CURRENT_SINK         PM_WLED_CTNL_REG(0x4F)
+#define LEDn_FULL_SCALE_CURRENT(n)   (PM_WLED_LED_CTNL_REG(n) + 0x2)
 
 #define PM_WLED_LED1_SINK_MASK       BIT(7)
 #define PM_WLED_LED2_SINK_MASK       BIT(6)
@@ -61,6 +64,8 @@
 	uint16_t led2_brightness;
 	uint16_t led3_brightness;
 	uint8_t max_duty_cycle;
+	uint8_t ovp;
+	uint8_t full_current_scale;;
 };
 
 void pm8x41_wled_config(struct pm8x41_wled_data *wled_ctrl);
diff --git a/dev/pmic/pm8x41/pm8x41.c b/dev/pmic/pm8x41/pm8x41.c
index ca7d230..93b5e57 100644
--- a/dev/pmic/pm8x41/pm8x41.c
+++ b/dev/pmic/pm8x41/pm8x41.c
@@ -35,12 +35,6 @@
 #include <pm8x41.h>
 #include <platform/timer.h>
 
-struct pm8x41_ldo ldo_data[] = {
-	LDO("LDO2",  NLDO_TYPE, 0x14100, LDO_RANGE_CTRL, LDO_STEP_CTRL, LDO_EN_CTL_REG),
-	LDO("LDO12", PLDO_TYPE, 0x14B00, LDO_RANGE_CTRL, LDO_STEP_CTRL, LDO_EN_CTL_REG),
-	LDO("LDO22", PLDO_TYPE, 0x15500, LDO_RANGE_CTRL, LDO_STEP_CTRL, LDO_EN_CTL_REG),
-};
-
 /* SPMI helper functions */
 uint8_t pm8x41_reg_read(uint32_t addr)
 {
@@ -260,34 +254,20 @@
 	REG_WRITE(PON_PS_HOLD_RESET_CTL2, BIT(S2_RESET_EN_BIT));
 }
 
-static struct pm8x41_ldo *ldo_get(const char *ldo_name)
-{
-	uint8_t i;
-	struct pm8x41_ldo *ldo = NULL;
-
-	for (i = 0; i < ARRAY_SIZE(ldo_data); i++) {
-		ldo = &ldo_data[i];
-		if (!strncmp(ldo->name, ldo_name, strlen(ldo_name)))
-			break;
-	}
-	return ldo;
-}
-
 /*
  * LDO set voltage, takes ldo name & voltage in UV as input
  */
-int pm8x41_ldo_set_voltage(const char *name, uint32_t voltage)
+int pm8x41_ldo_set_voltage(struct pm8x41_ldo *ldo, uint32_t voltage)
 {
 	uint32_t range = 0;
 	uint32_t step = 0;
 	uint32_t mult = 0;
 	uint32_t val = 0;
 	uint32_t vmin = 0;
-	struct pm8x41_ldo *ldo;
 
-	ldo = ldo_get(name);
-	if (!ldo) {
-		dprintf(CRITICAL, "LDO requsted is not supported: %s\n", name);
+	if (!ldo)
+	{
+		dprintf(CRITICAL, "LDO pointer is invalid: %p\n", ldo);
 		return 1;
 	}
 
@@ -300,21 +280,29 @@
 	 * Select range, step & vmin based on input voltage & type of LDO
 	 * LDO can operate in low, mid, high power mode
 	 */
-	if (ldo->type == PLDO_TYPE) {
-		if (voltage < PLDO_UV_MIN) {
+	if (ldo->type == PLDO_TYPE)
+	{
+		if (voltage < PLDO_UV_MIN)
+		{
 			range = 2;
 			step = PLDO_UV_STEP_LOW;
 			vmin = PLDO_UV_VMIN_LOW;
-		} else if (voltage < PDLO_UV_MID) {
+		}
+		else if (voltage < PDLO_UV_MID)
+		{
 			range = 3;
 			step = PLDO_UV_STEP_MID;
 			vmin = PLDO_UV_VMIN_MID;
-		} else {
+		}
+		else
+		{
 			range = 4;
 			step = PLDO_UV_STEP_HIGH;
 			vmin = PLDO_UV_VMIN_HIGH;
 		}
-	} else {
+	}
+	else
+	{
 		range = 2;
 		step = NLDO_UV_STEP;
 		vmin = NLDO_UV_VMIN_LOW;
@@ -325,12 +313,12 @@
 	/* Set Range in voltage ctrl register */
 	val = 0x0;
 	val = range << LDO_RANGE_SEL_BIT;
-	REG_WRITE((ldo->base + ldo->range_reg), val);
+	REG_WRITE((ldo->base + LDO_RANGE_CTRL), val);
 
 	/* Set multiplier in voltage ctrl register */
 	val = 0x0;
 	val = mult << LDO_VSET_SEL_BIT;
-	REG_WRITE((ldo->base + ldo->step_reg), val);
+	REG_WRITE((ldo->base + LDO_STEP_CTRL), val);
 
 	return 0;
 }
@@ -338,14 +326,13 @@
 /*
  * Enable or Disable LDO
  */
-int pm8x41_ldo_control(const char *name, uint8_t enable)
+int pm8x41_ldo_control(struct pm8x41_ldo *ldo, uint8_t enable)
 {
 	uint32_t val = 0;
-	struct pm8x41_ldo *ldo;
 
-	ldo = ldo_get(name);
-	if (!ldo) {
-		dprintf(CRITICAL, "Requested LDO is not supported : %s\n", name);
+	if (!ldo)
+	{
+		dprintf(CRITICAL, "LDO pointer is invalid: %p\n", ldo);
 		return 1;
 	}
 
@@ -355,7 +342,7 @@
 	else
 		val = (0 << LDO_VREG_ENABLE_BIT);
 
-	REG_WRITE((ldo->base + ldo->enable_reg), val);
+	REG_WRITE((ldo->base + LDO_EN_CTL_REG), val);
 
 	return 0;
 }
@@ -369,3 +356,19 @@
 {
 	return REG_READ(PON_PON_REASON1);
 }
+
+void pm8x41_enable_mpp(struct pm8x41_mpp *mpp, enum mpp_en_ctl enable)
+{
+	ASSERT(mpp);
+
+	REG_WRITE(mpp->base + MPP_EN_CTL, enable << MPP_EN_CTL_ENABLE_SHIFT);
+}
+
+void pm8x41_config_output_mpp(struct pm8x41_mpp *mpp)
+{
+	ASSERT(mpp);
+
+	REG_WRITE(mpp->base + MPP_DIG_VIN_CTL, mpp->vin);
+
+	REG_WRITE(mpp->base + MPP_MODE_CTL, mpp->mode | (MPP_DIGITAL_OUTPUT << MPP_MODE_CTL_MODE_SHIFT));
+}
diff --git a/dev/pmic/pm8x41/pm8x41_wled.c b/dev/pmic/pm8x41/pm8x41_wled.c
index 5693590..fd8b48f 100644
--- a/dev/pmic/pm8x41/pm8x41_wled.c
+++ b/dev/pmic/pm8x41/pm8x41_wled.c
@@ -48,6 +48,10 @@
 	REG_WRITE(PM_WLED_LED3_BRIGHTNESS_MSB, ((wled_ctrl->led3_brightness >> 8) & 0xFF));
 
 	REG_WRITE(PM_WLED_MAX_DUTY_CYCLE, wled_ctrl->max_duty_cycle);
+	REG_WRITE(PM_WLED_OVP, wled_ctrl->ovp);
+	REG_WRITE(LEDn_FULL_SCALE_CURRENT(1), wled_ctrl->full_current_scale);
+	REG_WRITE(LEDn_FULL_SCALE_CURRENT(2), wled_ctrl->full_current_scale);
+	REG_WRITE(LEDn_FULL_SCALE_CURRENT(3), wled_ctrl->full_current_scale);
 
 	dprintf(SPEW, "WLED Configuration Success.\n");
 
diff --git a/include/platform.h b/include/platform.h
index 1c5b27e..aa63431 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -23,6 +23,8 @@
 #ifndef __PLATFORM_H
 #define __PLATFORM_H
 
+#include <dload_util.h>
+
 #define PA(x) platform_get_virt_to_phys_mapping(x)
 #define VA(x) platform_get_phys_to_virt_mapping(x)
 
@@ -50,6 +52,6 @@
 unsigned check_reboot_mode(void);
 void platform_uninit_timer(void);
 void reboot_device(unsigned);
-int set_download_mode(void);
+int set_download_mode(enum dload_mode mode);
 
 #endif
diff --git a/platform/msm8226/include/platform/iomap.h b/platform/msm8226/include/platform/iomap.h
index 2fe4b42..851e798 100644
--- a/platform/msm8226/include/platform/iomap.h
+++ b/platform/msm8226/include/platform/iomap.h
@@ -42,7 +42,8 @@
 #define MSM_SHARED_IMEM_BASE        0xFE805000
 
 #define RESTART_REASON_ADDR         (MSM_SHARED_IMEM_BASE + 0x65C)
-#define FORCE_DLOAD_MODE_ADDR       (MSM_SHARED_IMEM_BASE + 0xFE0)
+#define DLOAD_MODE_ADDR             (MSM_SHARED_IMEM_BASE + 0x0)
+#define EMERGENCY_DLOAD_MODE_ADDR   (MSM_SHARED_IMEM_BASE + 0xFE0)
 
 #define MSM_GIC_DIST_BASE           APPS_SS_BASE
 #define MSM_GIC_CPU_BASE            (APPS_SS_BASE + 0x2000)
diff --git a/platform/msm8974/include/platform/iomap.h b/platform/msm8974/include/platform/iomap.h
index 12f0015..ff7ab1b 100644
--- a/platform/msm8974/include/platform/iomap.h
+++ b/platform/msm8974/include/platform/iomap.h
@@ -41,10 +41,10 @@
 #define SYSTEM_IMEM_BASE            0xFE800000
 #define MSM_SHARED_IMEM_BASE        0xFE805000
 
-#define RESTART_REASON_ADDR         (RPM_MSG_RAM_BASE     + 0x65C)
-#define RESTART_REASON_ADDR_V2      (MSM_SHARED_IMEM_BASE + 0x65C)
-
-#define FORCE_DLOAD_MODE_ADDR_V2    (MSM_SHARED_IMEM_BASE + 0xFE0)
+#define RESTART_REASON_ADDR             (RPM_MSG_RAM_BASE     + 0x65C)
+#define RESTART_REASON_ADDR_V2          (MSM_SHARED_IMEM_BASE + 0x65C)
+#define DLOAD_MODE_ADDR_V2              (MSM_SHARED_IMEM_BASE + 0x0)
+#define EMERGENCY_DLOAD_MODE_ADDR_V2    (MSM_SHARED_IMEM_BASE + 0xFE0)
 
 #define KPSS_BASE                   0xF9000000
 
diff --git a/platform/msm_shared/board.c b/platform/msm_shared/board.c
index 58bf4a3..dcc750d 100644
--- a/platform/msm_shared/board.c
+++ b/platform/msm_shared/board.c
@@ -142,6 +142,11 @@
 	return board.platform_hw;
 }
 
+uint32_t board_hardware_subtype(void)
+{
+	return board.platform_subtype;
+}
+
 uint8_t board_pmic_info(struct board_pmic_data *info, uint8_t num_ent)
 {
 	uint8_t i;
diff --git a/platform/msm_shared/debug.c b/platform/msm_shared/debug.c
index 36dc420..3349db7 100644
--- a/platform/msm_shared/debug.c
+++ b/platform/msm_shared/debug.c
@@ -30,12 +30,14 @@
  * SUCH DAMAGE.
  */
 
+#include <stdlib.h>
 #include <debug.h>
 #include <printf.h>
 #include <arch/arm/dcc.h>
 #include <dev/fbcon.h>
 #include <dev/uart.h>
 #include <platform/timer.h>
+#include <platform.h>
 
 static void write_dcc(char c)
 {
@@ -52,8 +54,49 @@
 		timeout--;
 	}
 }
+
+#if WITH_DEBUG_LOG_BUF
+
+#ifndef LK_LOG_BUF_SIZE
+#define LK_LOG_BUF_SIZE    (4096) /* align on 4k */
+#endif
+
+#define LK_LOG_COOKIE    0x474f4c52 /* "RLOG" in ASCII */
+
+struct lk_log {
+	struct lk_log_header {
+		unsigned cookie;
+		unsigned max_size;
+		unsigned size_written;
+		unsigned idx;
+	} header;
+	char data[LK_LOG_BUF_SIZE];
+};
+
+static struct lk_log log = {
+	.header = {
+		.cookie = LK_LOG_COOKIE,
+		.max_size = sizeof(log.data),
+		.size_written = 0,
+		.idx = 0,
+	},
+	.data = {0}
+};
+
+static void log_putc(char c)
+{
+	log.data[log.header.idx++] = c;
+	log.header.size_written++;
+	if (unlikely(log.header.idx >= log.header.max_size))
+		log.header.idx = 0;
+}
+#endif /* WITH_DEBUG_LOG_BUF */
+
 void _dputc(char c)
 {
+#if WITH_DEBUG_LOG_BUF
+	log_putc(c);
+#endif
 #if WITH_DEBUG_DCC
 	if (c == '\n') {
 		write_dcc('\r');
@@ -91,6 +134,16 @@
 
 void platform_halt(void)
 {
-	dprintf(INFO, "HALT: spinning forever...\n");
+	if (set_download_mode(NORMAL_DLOAD) == 0)
+	{
+		dprintf(CRITICAL, "HALT: reboot into dload mode...\n");
+		reboot_device(0);
+		dprintf(CRITICAL, "HALT: reboot_device failed\n");
+	}
+	else
+	{
+		dprintf(CRITICAL, "HALT: set_download_mode not supported\n");
+	}
+	dprintf(CRITICAL, "HALT: spinning forever...\n");
 	for (;;) ;
 }
diff --git a/platform/msm_shared/dev_tree.c b/platform/msm_shared/dev_tree.c
index f5dbb4e..de5384b 100644
--- a/platform/msm_shared/dev_tree.c
+++ b/platform/msm_shared/dev_tree.c
@@ -36,6 +36,15 @@
 #include <platform.h>
 #include <board.h>
 
+struct dt_entry_v1
+{
+	uint32_t platform_id;
+	uint32_t variant_id;
+	uint32_t soc_rev;
+	uint32_t offset;
+	uint32_t size;
+};
+
 extern int target_is_emmc_boot(void);
 extern uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset);
 /* TODO: This function needs to be moved to target layer to check violations
@@ -98,47 +107,118 @@
 	return NULL;
 }
 
-/* Function to return the pointer to the start of the correct device tree
+/* Returns 0 if the device tree is valid. */
+int dev_tree_validate(struct dt_table *table, unsigned int page_size)
+{
+	int dt_entry_size;
+
+	/* Validate the device tree table header */
+	if(table->magic != DEV_TREE_MAGIC) {
+		dprintf(CRITICAL, "ERROR: Bad magic in device tree table \n");
+		return -1;
+	}
+
+	if (table->version == DEV_TREE_VERSION_V1) {
+		dt_entry_size = sizeof(struct dt_entry_v1);
+	} else if (table->version == DEV_TREE_VERSION_V2) {
+		dt_entry_size = sizeof(struct dt_entry);
+	} else {
+		dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
+				table->version);
+		return -1;
+	}
+
+	/* Restriction that the device tree entry table should be less than a page*/
+	ASSERT(((table->num_entries * dt_entry_size)+ DEV_TREE_HEADER_SIZE) < page_size);
+
+	return 0;
+}
+
+/* Function to obtain the index information for the correct device tree
  *  based on the platform data.
+ *  If a matching device tree is found, the information is returned in the
+ *  "dt_entry_info" out parameter and a function value of 0 is returned, otherwise
+ *  a non-zero function value is returned.
  */
-struct dt_entry * dev_tree_get_entry_ptr(struct dt_table *table)
+int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)
 {
 	uint32_t i;
-	struct dt_entry *dt_entry_ptr;
-	struct dt_entry *latest_dt_entry = NULL;
+	unsigned char *table_ptr;
+	struct dt_entry dt_entry_buf_1;
+	struct dt_entry dt_entry_buf_2;
+	struct dt_entry *cur_dt_entry;
+	struct dt_entry *best_match_dt_entry;
+	struct dt_entry_v1 *dt_entry_v1;
 
-	dt_entry_ptr = (struct dt_entry *)((char *)table + DEV_TREE_HEADER_SIZE);
+	if (!dt_entry_info) {
+		dprintf(CRITICAL, "ERROR: Bad parameter passed to %s \n",
+				__func__);
+		return -1;
+	}
+
+	table_ptr = (unsigned char *)table + DEV_TREE_HEADER_SIZE;
+	cur_dt_entry = &dt_entry_buf_1;
+	best_match_dt_entry = NULL;
 
 	for(i = 0; i < table->num_entries; i++)
 	{
+		memset(cur_dt_entry, 0, sizeof(struct dt_entry));
+		switch(table->version) {
+		case DEV_TREE_VERSION_V1:
+			dt_entry_v1 = (struct dt_entry_v1 *)table_ptr;
+			cur_dt_entry->platform_id = dt_entry_v1->platform_id;
+			cur_dt_entry->variant_id = dt_entry_v1->variant_id;
+			cur_dt_entry->soc_rev = dt_entry_v1->soc_rev;
+			cur_dt_entry->board_hw_subtype = board_hardware_subtype();
+			cur_dt_entry->offset = dt_entry_v1->offset;
+			cur_dt_entry->size = dt_entry_v1->size;
+			table_ptr += sizeof(struct dt_entry_v1);
+			break;
+		case DEV_TREE_VERSION_V2:
+			memcpy(cur_dt_entry, (struct dt_entry *)table_ptr,
+				   sizeof(struct dt_entry));
+			table_ptr += sizeof(struct dt_entry);
+			break;
+		default:
+			dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
+					table->version);
+			return -1;
+		}
+
 		/* DTBs are stored in the ascending order of soc revision.
 		 * For eg: Rev0..Rev1..Rev2 & so on.
 		 * we pickup the DTB with highest soc rev number which is less
 		 * than or equal to actual hardware
 		 */
-		if((dt_entry_ptr->platform_id == board_platform_id()) &&
-		   (dt_entry_ptr->variant_id == board_hardware_id()) &&
-		   (dt_entry_ptr->soc_rev == board_soc_version()))
-			{
-				return dt_entry_ptr;
+		if((cur_dt_entry->platform_id == board_platform_id()) &&
+		   (cur_dt_entry->variant_id == board_hardware_id()) &&
+		   (cur_dt_entry->board_hw_subtype == board_hardware_subtype()))
+		{
+			if(cur_dt_entry->soc_rev == board_soc_version()) {
+				/* copy structure */
+				*dt_entry_info = *cur_dt_entry;
+				return 0;
+			} else if (cur_dt_entry->soc_rev < board_soc_version()){
+				/* Keep this as the next best candidate. */
+				if (!best_match_dt_entry) {
+					best_match_dt_entry = cur_dt_entry;
+					cur_dt_entry = &dt_entry_buf_2;
+				} else {
+					/* Swap dt_entry buffers */
+					struct dt_entry *temp = cur_dt_entry;
+					cur_dt_entry = best_match_dt_entry;
+					best_match_dt_entry = temp;
+				}
 			}
-		/* if the exact match not found, return the closest match
-		 * assuming it to be the nearest soc version
-		 */
-		if((dt_entry_ptr->platform_id == board_platform_id()) &&
-		  (dt_entry_ptr->variant_id == board_hardware_id()) &&
-		  (dt_entry_ptr->soc_rev <= board_soc_version())) {
-			latest_dt_entry = dt_entry_ptr;
 		}
-		dt_entry_ptr++;
 	}
 
-	if (latest_dt_entry) {
-		dprintf(SPEW, "Loading DTB with SOC version:%x\n", latest_dt_entry->soc_rev);
-		return latest_dt_entry;
+	if (best_match_dt_entry) {
+		*dt_entry_info = *best_match_dt_entry;
+		return 0;
 	}
 
-	return NULL;
+	return -1;
 }
 
 /* Function to add the first RAM partition info to the device tree.
diff --git a/platform/msm_shared/dload_util.c b/platform/msm_shared/dload_util.c
index 4b7d08b..06140f2 100644
--- a/platform/msm_shared/dload_util.c
+++ b/platform/msm_shared/dload_util.c
@@ -28,18 +28,34 @@
 
 #include <stdlib.h>
 #include <reg.h>
+#include <dload_util.h>
 
-#define FORCE_DLOAD_COOKIE_0    0x322A4F99
-#define FORCE_DLOAD_COOKIE_1    0xC67E4350
-#define FORCE_DLOAD_COOKIE_2    0x77777777
+#define NORMAL_DLOAD_COOKIE_0       0xE47B337D
+#define NORMAL_DLOAD_COOKIE_1       0xCE14091A
+
+#define EMERGENCY_DLOAD_COOKIE_0    0x322A4F99
+#define EMERGENCY_DLOAD_COOKIE_1    0xC67E4350
+#define EMERGENCY_DLOAD_COOKIE_2    0x77777777
 
 extern void dsb();
 
-void dload_util_write_cookie(uint32_t target_dload_mode_addr)
+void dload_util_write_cookie(uint32_t target_dload_mode_addr,
+		enum dload_mode mode)
 {
-	writel(FORCE_DLOAD_COOKIE_0, target_dload_mode_addr);
-	writel(FORCE_DLOAD_COOKIE_1, target_dload_mode_addr + sizeof(uint32_t));
-	writel(FORCE_DLOAD_COOKIE_2, target_dload_mode_addr + 2 * sizeof(uint32_t));
+	if (mode == NORMAL_DLOAD)
+	{
+		writel(NORMAL_DLOAD_COOKIE_0, target_dload_mode_addr);
+		writel(NORMAL_DLOAD_COOKIE_1,
+				target_dload_mode_addr + sizeof(uint32_t));
+	}
+	else
+	{
+		writel(EMERGENCY_DLOAD_COOKIE_0, target_dload_mode_addr);
+		writel(EMERGENCY_DLOAD_COOKIE_1,
+				target_dload_mode_addr + sizeof(uint32_t));
+		writel(EMERGENCY_DLOAD_COOKIE_2,
+				target_dload_mode_addr + 2 * sizeof(uint32_t));
+	}
 
 	dsb();
 }
diff --git a/platform/msm_shared/include/board.h b/platform/msm_shared/include/board.h
index f863a26..ffc65e8 100644
--- a/platform/msm_shared/include/board.h
+++ b/platform/msm_shared/include/board.h
@@ -60,5 +60,5 @@
 uint32_t board_hardware_id();
 uint8_t board_pmic_info(struct board_pmic_data *, uint8_t num_ent);
 uint32_t board_soc_version();
-
+uint32_t board_hardware_subtype(void);
 #endif
diff --git a/platform/msm_shared/include/dev_tree.h b/platform/msm_shared/include/dev_tree.h
index 2c216aa..d0b0ca8 100644
--- a/platform/msm_shared/include/dev_tree.h
+++ b/platform/msm_shared/include/dev_tree.h
@@ -34,7 +34,8 @@
 #define DEV_TREE_SUCCESS        0
 #define DEV_TREE_MAGIC          0x54444351 /* "QCDT" */
 #define DEV_TREE_MAGIC_LEN      4
-#define DEV_TREE_VERSION        1
+#define DEV_TREE_VERSION_V1     1
+#define DEV_TREE_VERSION_V2     2
 #define DEV_TREE_HEADER_SIZE    12
 
 #define DTB_MAGIC               0xedfe0dd0
@@ -46,6 +47,7 @@
 {
 	uint32_t platform_id;
 	uint32_t variant_id;
+	uint32_t board_hw_subtype;
 	uint32_t soc_rev;
 	uint32_t offset;
 	uint32_t size;
@@ -64,7 +66,8 @@
 	DT_OP_FAILURE = -1,
 };
 
-struct dt_entry * dev_tree_get_entry_ptr(struct dt_table *);
+int dev_tree_validate(struct dt_table *table, unsigned int page_size);
+int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info);
 int update_device_tree(void *, const char *, void *, unsigned);
 int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint32_t size, uint32_t addr);
 void *dev_tree_appended(void *kernel, void *tags, uint32_t kernel_size);
diff --git a/platform/msm_shared/include/dload_util.h b/platform/msm_shared/include/dload_util.h
index 71d045d..8415773 100644
--- a/platform/msm_shared/include/dload_util.h
+++ b/platform/msm_shared/include/dload_util.h
@@ -31,6 +31,12 @@
 
 #include <sys/types.h>
 
-void dload_util_write_cookie(uint32_t target_dload_mode_addr);
+enum dload_mode {
+	NORMAL_DLOAD,
+	EMERGENCY_DLOAD
+};
+
+void dload_util_write_cookie(uint32_t target_dload_mode_addr,
+		enum dload_mode mode);
 
 #endif
diff --git a/platform/msm_shared/include/mmc.h b/platform/msm_shared/include/mmc.h
index f1c9762..12181b3 100644
--- a/platform/msm_shared/include/mmc.h
+++ b/platform/msm_shared/include/mmc.h
@@ -284,6 +284,7 @@
 #define CMD2_ALL_SEND_CID                2
 #define CMD3_SEND_RELATIVE_ADDR          3
 #define CMD4_SET_DSR                     4
+#define CMD5_SLEEP_AWAKE                 5
 #define CMD6_SWITCH_FUNC                 6
 #define ACMD6_SET_BUS_WIDTH              6	/* SD card */
 #define CMD7_SELECT_DESELECT_CARD        7
@@ -422,6 +423,9 @@
 #define MMC_BOOT_SD_DEV_READY             0x80000000
 #define MMC_BOOT_SD_SWITCH_HS             0x80FFFFF1
 
+/* Put the card to sleep */
+#define MMC_CARD_SLEEP                    (1 << 15)
+
 /* Data structure definitions */
 struct mmc_boot_command {
 	unsigned int cmd_index;
@@ -562,6 +566,7 @@
 #define MAX_FILE_ENTRIES          20
 
 #define MMC_RCA 2
+#define MMC_CARD_RCA_BIT                  16
 
 /* Can be used to unpack array of upto 32 bits data */
 #define UNPACK_BITS(array, start, len, size_of)                               \
@@ -618,5 +623,6 @@
 uint8_t card_supports_ddr_mode();
 uint8_t card_supports_hs200_mode();
 uint64_t mmc_get_device_capacity();
+void mmc_put_card_to_sleep(void);
 #endif
 #endif
diff --git a/platform/msm_shared/include/mmc_sdhci.h b/platform/msm_shared/include/mmc_sdhci.h
index 99174bf..6aa323d 100644
--- a/platform/msm_shared/include/mmc_sdhci.h
+++ b/platform/msm_shared/include/mmc_sdhci.h
@@ -37,6 +37,7 @@
 #define CMD2_ALL_SEND_CID                         2
 #define CMD3_SEND_RELATIVE_ADDR                   3
 #define CMD4_SET_DSR                              4
+#define CMD5_SLEEP_AWAKE                          5
 #define CMD6_SWITCH_FUNC                          6
 #define CMD7_SELECT_DESELECT_CARD                 7
 #define CMD8_SEND_EXT_CSD                         8
@@ -80,6 +81,7 @@
 #define MMC_SWITCH_FUNC_ERR_FLAG                  (1 << 7)
 #define MMC_STATUS_INACTIVE                       0
 #define MMC_STATUS_ACTIVE                         1
+#define MMC_READY_FOR_DATA                        (1 << 8)
 
 /* EXT_CSD */
 /* Offsets in the ext csd */
@@ -94,29 +96,40 @@
 #define MMC_PART_CONFIG                           179
 #define MMC_ERASE_GRP_DEF                         175
 #define MMC_USR_WP                                171
+#define MMC_HC_ERASE_GRP_SIZE                     224
 
 /* Values for ext csd fields */
 #define MMC_HS_TIMING                             0x1
 #define MMC_HS200_TIMING                          0x2
 #define MMC_ACCESS_WRITE                          0x3
+#define MMC_SET_BIT                               0x1
 #define MMC_HS_DDR_MODE                           (BIT(2) | BIT(3))
 #define MMC_HS_HS200_MODE                         (BIT(4) | BIT(5))
 #define MMC_SEC_COUNT4_SHIFT                      24
 #define MMC_SEC_COUNT3_SHIFT                      16
 #define MMC_SEC_COUNT2_SHIFT                      8
+#define MMC_HC_ERASE_MULT                         (512 * 1024)
 
 /* Command related */
 #define MMC_MAX_COMMAND_RETRY                     1000
+#define MMC_MAX_CARD_STAT_RETRY                   10000
 #define MMC_RD_BLOCK_LEN                          512
 #define MMC_WR_BLOCK_LEN                          512
 #define MMC_R1_BLOCK_LEN_ERR                      (1 << 29)
 #define MMC_R1_ADDR_ERR                           (1 << 30)
+#define MMC_R1_WP_ERASE_SKIP                      BIT(15)
+#define MMC_US_PERM_WP_DIS                        BIT(4)
+#define MMC_US_PWR_WP_DIS                         BIT(3)
+#define MMC_US_PERM_WP_EN                         BIT(2)
+#define MMC_US_PWR_WP_EN                          BIT(0)
 
 /* RCA of the card */
 #define MMC_RCA                                   2
+#define MMC_CARD_RCA_BIT                          16
 
 /* Misc card macros */
 #define MMC_BLK_SZ                                512
+#define MMC_CARD_SLEEP                            (1 << 15)
 
 /* Clock rates */
 #define MMC_CLK_400KHZ                            400000
@@ -128,6 +141,8 @@
 #define MMC_CLK_96MHZ                             96000000
 #define MMC_CLK_200MHZ                            200000000
 
+#define MMC_ADDR_OUT_OF_RANGE(resp)              ((resp >> 31) & 0x01)
+
 /* Can be used to unpack array of upto 32 bits data */
 #define UNPACK_BITS(array, start, len, size_of)           \
     ({                                                    \
@@ -218,4 +233,12 @@
 uint32_t mmc_sdhci_read(struct mmc_device *dev, void *dest, uint64_t blk_addr, uint32_t num_blocks);
 /* API: Write requried number of blocks from source to card */
 uint32_t mmc_sdhci_write(struct mmc_device *dev, void *src, uint64_t blk_addr, uint32_t num_blocks);
+/* API: Erase len bytes (after converting to number of erase groups), from specified address */
+uint32_t mmc_sdhci_erase(struct mmc_device *dev, uint32_t blk_addr, uint64_t len);
+/* API: Write protect or release len bytes (after converting to number of write protect groups) from specified start address*/
+uint32_t mmc_set_clr_power_on_wp_user(struct mmc_device *dev, uint32_t addr, uint64_t len, uint8_t set_clr);
+/* API: Get the WP status of write protect groups starting at addr */
+uint32_t mmc_get_wp_status(struct mmc_device *dev, uint32_t addr, uint8_t *wp_status);
+/* API: Put the mmc card in sleep mode */
+void mmc_put_card_to_sleep(struct mmc_device *dev);
 #endif
diff --git a/platform/msm_shared/include/sdhci.h b/platform/msm_shared/include/sdhci.h
index 0c15c06..20861fc 100644
--- a/platform/msm_shared/include/sdhci.h
+++ b/platform/msm_shared/include/sdhci.h
@@ -88,7 +88,7 @@
 struct desc_entry {
 	uint16_t tran_att;   /* Attribute for transfer data */
 	uint16_t len;        /* Length of data */
-	void *addr;          /* Address of the data */
+	uint32_t addr;       /* Address of the data */
 };
 
 /*
@@ -262,7 +262,7 @@
 #define SDHCI_ADMA_MASK                           BIT(9)
 #define SDHCI_READ_MODE                           BIT(4)
 #define SDHCI_SWITCH_CMD                          6
-#define SDHCI_CMD_TIMEOUT                         0xE
+#define SDHCI_CMD_TIMEOUT                         0xF
 #define SDHCI_MAX_CMD_RETRY                       10000
 #define SDHCI_MAX_TRANS_RETRY                     100000
 
diff --git a/platform/msm_shared/mmc.c b/platform/msm_shared/mmc.c
index 851bb08..7783f10 100644
--- a/platform/msm_shared/mmc.c
+++ b/platform/msm_shared/mmc.c
@@ -552,8 +552,10 @@
 	/* 2a. Write command index in CMD_INDEX field */
 	cmd_index = cmd->cmd_index;
 	mmc_cmd |= cmd->cmd_index;
-	/* 2b. Set RESPONSE bit to 1 for all cmds except CMD0 */
-	if (cmd_index != CMD0_GO_IDLE_STATE) {
+	/* 2b. Set RESPONSE bit to 1 for all cmds except CMD0
+	 * And dont set RESPONSE bit for commands with no response
+	 */
+	if (cmd_index != CMD0_GO_IDLE_STATE && cmd->resp_type != MMC_BOOT_RESP_NONE) {
 		mmc_cmd |= MMC_BOOT_MCI_CMD_RESPONSE;
 	}
 
@@ -3405,3 +3407,32 @@
 {
 	return mmc_card.capacity;
 }
+
+void mmc_put_card_to_sleep(void)
+{
+	uint32_t mmc_ret;
+	struct mmc_boot_command cmd = {0};
+
+	cmd.cmd_index = CMD7_SELECT_DESELECT_CARD;
+	cmd.argument = 0x00000000;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_NONE;
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS)
+	{
+		dprintf(CRITICAL, "card deselect error: %d\n", mmc_ret);
+		return;
+	}
+
+	cmd.cmd_index = CMD5_SLEEP_AWAKE;
+	cmd.argument = (mmc_card.rca << MMC_CARD_RCA_BIT) | MMC_CARD_SLEEP;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1B;
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS)
+		dprintf(CRITICAL, "card sleep error: %d\n", mmc_ret);
+}
diff --git a/platform/msm_shared/mmc_sdhci.c b/platform/msm_shared/mmc_sdhci.c
index b565d9e..1e6aaa8 100644
--- a/platform/msm_shared/mmc_sdhci.c
+++ b/platform/msm_shared/mmc_sdhci.c
@@ -1313,3 +1313,359 @@
 
 	return mmc_ret;
 }
+
+/*
+ * Send the erase group start address using CMD35
+ */
+static uint32_t mmc_send_erase_grp_start(struct mmc_device *dev, uint32_t erase_start)
+{
+	struct mmc_command cmd;
+
+	memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.cmd_index = CMD35_ERASE_GROUP_START;
+	cmd.argument = erase_start;
+	cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+	cmd.resp_type = SDHCI_CMD_RESP_R1;
+
+	/* send command */
+	if (sdhci_send_command(&dev->host, &cmd))
+		return 1;
+
+	/*
+	 * CMD35 on failure returns address out of range error
+	 */
+	if (MMC_ADDR_OUT_OF_RANGE(cmd.resp[0]))
+	{
+		dprintf(CRITICAL, "Address for CMD35 is out of range\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Send the erase group end address using CMD36
+ */
+static uint32_t mmc_send_erase_grp_end(struct mmc_device *dev, uint32_t erase_end)
+{
+	struct mmc_command cmd;
+
+	memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.cmd_index = CMD36_ERASE_GROUP_END;
+	cmd.argument = erase_end;
+	cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+	cmd.resp_type = SDHCI_CMD_RESP_R1;
+
+	/* send command */
+	if (sdhci_send_command(&dev->host, &cmd))
+		return 1;
+
+	/*
+	 * CMD3 on failure returns address out of range error
+	 */
+	if (MMC_ADDR_OUT_OF_RANGE(cmd.resp[0]))
+	{
+		dprintf(CRITICAL, "Address for CMD36 is out of range\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Send the erase CMD38, to erase the selected erase groups
+ */
+static uint32_t mmc_send_erase(struct mmc_device *dev)
+{
+	struct mmc_command cmd;
+	uint32_t status;
+	uint32_t retry;
+
+	memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.cmd_index = CMD38_ERASE;
+	cmd.argument = 0x00000000;
+	cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+	cmd.resp_type = SDHCI_CMD_RESP_R1B;
+
+	/* send command */
+	if (sdhci_send_command(&dev->host, &cmd))
+		return 1;
+
+	do
+	{
+		if (mmc_get_card_status(&dev->host, &dev->card, &status))
+		{
+			dprintf(CRITICAL, "Failed to get card status after erase\n");
+			return 1;
+		}
+		/* Check if the response of erase command has eras skip status set */
+		if (status & MMC_R1_WP_ERASE_SKIP)
+			dprintf(CRITICAL, "Write Protect set for the region, only partial space was erased\n");
+
+		retry++;
+		udelay(1000);
+		if (retry == MMC_MAX_CARD_STAT_RETRY)
+		{
+			dprintf(CRITICAL, "Card status check timed out after sending erase command\n");
+			return 1;
+		}
+	} while(!(status & MMC_READY_FOR_DATA) || (MMC_CARD_STATUS(status) == MMC_PROG_STATE));
+
+
+	return 0;
+}
+
+
+/*
+ * Function: mmc sdhci erase
+ * Arg     : mmc device structure, block address and length
+ * Return  : 0 on Success, non zero on failure
+ * Flow    : Fill in the command structure & send the command
+ */
+uint32_t mmc_sdhci_erase(struct mmc_device *dev, uint32_t blk_addr, uint64_t len)
+{
+	uint32_t erase_unit_sz = 0;
+	uint32_t erase_start;
+	uint32_t erase_end;
+	uint32_t blk_end;
+	uint32_t num_erase_grps;
+	uint32_t *out;
+
+	/*
+	 * Calculate the erase unit size as per the emmc specification v4.5
+	 */
+	if (dev->card.ext_csd[MMC_ERASE_GRP_DEF])
+		erase_unit_sz = (MMC_HC_ERASE_MULT * dev->card.ext_csd[MMC_HC_ERASE_GRP_SIZE]) / MMC_BLK_SZ;
+	else
+		erase_unit_sz = (dev->card.csd.erase_grp_size + 1) * (dev->card.csd.erase_grp_mult + 1);
+
+	/* Convert length in blocks */
+	len = len / MMC_BLK_SZ;
+
+	if (len < erase_unit_sz)
+	{
+		dprintf(CRITICAL, "Requested length is less than min erase group size\n");
+		return 1;
+	}
+
+	/* Calculate erase groups based on the length in blocks */
+	num_erase_grps = len / erase_unit_sz;
+
+	/* Start address of the erase range */
+	erase_start = blk_addr;
+
+	/* Last address of the erase range */
+	erase_end = blk_addr + ((num_erase_grps - 1) * erase_unit_sz);
+
+	/* Boundary check for overlap */
+	blk_end = blk_addr + len;
+
+	if (erase_end > blk_end)
+	{
+		dprintf(CRITICAL, "The erase group overlaps the max requested for erase\n");
+		erase_end -= erase_unit_sz;
+	}
+
+	/* Send CMD35 for erase group start */
+	if (mmc_send_erase_grp_start(dev, erase_start))
+	{
+		dprintf(CRITICAL, "Failed to send erase grp start address\n");
+		return 1;
+	}
+
+	/* Send CMD36 for erase group end */
+	if (mmc_send_erase_grp_end(dev, erase_end))
+	{
+		dprintf(CRITICAL, "Failed to send erase grp end address\n");
+		return 1;
+	}
+
+	/* Send CMD38 to perform erase */
+	if (mmc_send_erase(dev))
+	{
+		dprintf(CRITICAL, "Failed to erase the specified partition\n");
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Function: mmc get wp status
+ * Arg     : mmc device structure, block address and buffer for getting wp status
+ * Return  : 0 on Success, 1 on Failure
+ * Flow    : Get the WP group status by sending CMD31
+ */
+uint32_t mmc_get_wp_status(struct mmc_device *dev, uint32_t addr, uint8_t *wp_status)
+{
+	struct mmc_command cmd;
+
+	memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.cmd_index = CMD31_SEND_WRITE_PROT_TYPE;
+	cmd.argument = addr;
+	cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+	cmd.resp_type = SDHCI_CMD_RESP_R1;
+	cmd.trans_mode = SDHCI_MMC_READ;
+	cmd.data_present = 0x1;
+	cmd.data.data_ptr = wp_status;
+	cmd.data.num_blocks = 0x1;
+	cmd.data.blk_sz = 0x8;
+
+	if (sdhci_send_command(&dev->host, &cmd))
+	{
+		dprintf(CRITICAL, "Failed to get status of write protect bits\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Function: mmc set/clear WP on user area
+ * Arg     : mmc device structure, block address,len, & flag to set or clear
+ * Return  : 0 on success, 1 on failure
+ * Flow    : Function to set/clear power on write protect on user area
+ */
+
+uint32_t mmc_set_clr_power_on_wp_user(struct mmc_device *dev, uint32_t addr, uint64_t len, uint8_t set_clr)
+{
+	struct mmc_command cmd;
+	uint32_t wp_grp_size;
+	uint32_t status;
+	uint32_t num_wp_grps;
+	uint32_t ret;
+	uint32_t retry;
+	uint32_t i;
+
+	memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+	/* Convert len into blocks */
+	len = len / MMC_BLK_SZ;
+
+	/* Disable PERM WP */
+	ret = mmc_switch_cmd(&dev->host, &dev->card, MMC_SET_BIT, MMC_USR_WP, MMC_US_PERM_WP_DIS);
+
+	if (ret)
+	{
+		dprintf(CRITICAL, "Failed to Disable PERM WP\n");
+		return ret;
+	}
+
+	/* Read the default values for user WP */
+	ret = mmc_get_ext_csd(&dev->host, &dev->card);
+
+	if (ret)
+	{
+		dprintf(CRITICAL, "Failed to read ext csd for the card\n");
+		return ret;
+	}
+
+	/* Check if user power on WP is disabled or perm WP is enabled */
+	if ((dev->card.ext_csd[MMC_USR_WP] & MMC_US_PWR_WP_DIS)
+		|| (dev->card.ext_csd[MMC_USR_WP] & MMC_US_PERM_WP_EN))
+	{
+		dprintf(CRITICAL, "Power on protection is disabled, cannot be set\n");
+		return 1;
+	}
+
+	/* Calculate the wp grp size */
+	if (dev->card.ext_csd[MMC_ERASE_GRP_DEF])
+		wp_grp_size = MMC_HC_ERASE_MULT * dev->card.ext_csd[MMC_HC_ERASE_GRP_SIZE] / MMC_BLK_SZ;
+	else
+		wp_grp_size = (dev->card.csd.wp_grp_size + 1) * (dev->card.csd.erase_grp_size + 1) \
+					  * (dev->card.csd.erase_grp_mult + 1);
+
+
+	if (len < wp_grp_size)
+	{
+		dprintf(CRITICAL, "Length is less than min WP size, WP was not set\n");
+		return 1;
+	}
+
+	/* Set power on USER WP */
+	ret = mmc_switch_cmd(&dev->host, &dev->card, MMC_SET_BIT, MMC_USR_WP, MMC_US_PWR_WP_EN);
+
+	if (ret)
+	{
+		dprintf(CRITICAL, "Failed to set power on WP for user\n");
+		return ret;
+	}
+
+	num_wp_grps = ROUNDUP(len, wp_grp_size) / wp_grp_size;
+
+	if (set_clr)
+		cmd.cmd_index = CMD28_SET_WRITE_PROTECT;
+	else
+		cmd.cmd_index = CMD29_CLEAR_WRITE_PROTECT;
+
+	cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+	cmd.resp_type = SDHCI_CMD_RESP_R1B;
+
+	for(i = 0; i < num_wp_grps; i++)
+	{
+		cmd.argument = addr + (i * wp_grp_size);
+
+		if (sdhci_send_command(&dev->host, &cmd))
+			return 1;
+
+		/* CMD28/CMD29 On failure returns address out of range error */
+		if (MMC_ADDR_OUT_OF_RANGE(cmd.resp[0]))
+		{
+			dprintf(CRITICAL, "Address for CMD28/29 is out of range\n");
+			return 1;
+		}
+
+		/* Check the card status */
+		do
+		{
+			if (mmc_get_card_status(&dev->host, &dev->card, &status))
+			{
+				dprintf(CRITICAL, "Failed to get card status afterapplying write protect\n");
+				return 1;
+			}
+
+		/* Time out for WP command */
+		retry++;
+		udelay(1000);
+		if (retry == MMC_MAX_CARD_STAT_RETRY)
+		{
+			dprintf(CRITICAL, "Card status timed out after sending write protect command\n");
+			return 1;
+		}
+		} while (!(status & MMC_READY_FOR_DATA) || (MMC_CARD_STATUS(status) == MMC_PROG_STATE));
+
+	}
+
+	return 0;
+}
+
+/* Function to put the mmc card to sleep */
+void mmc_put_card_to_sleep(struct mmc_device *dev)
+{
+	struct mmc_command cmd = {0};
+	struct mmc_card *card = &dev->card;
+
+	cmd.cmd_index = CMD7_SELECT_DESELECT_CARD;
+	cmd.argument = 0x00000000;
+	cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+	cmd.resp_type = SDHCI_CMD_RESP_NONE;
+
+	/* send command */
+	if(sdhci_send_command(&dev->host, &cmd))
+	{
+		dprintf(CRITICAL, "card deselect error: %s\n", __func__);
+		return;
+	}
+
+	cmd.cmd_index = CMD5_SLEEP_AWAKE;
+	cmd.argument = (card->rca << MMC_CARD_RCA_BIT) | MMC_CARD_SLEEP;
+	cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+	cmd.resp_type = SDHCI_CMD_RESP_R1B;
+
+	/* send command */
+	if(sdhci_send_command(&dev->host, &cmd))
+		dprintf(CRITICAL, "card sleep error: %s\n", __func__);
+}
diff --git a/platform/msm_shared/mmc_wrapper.c b/platform/msm_shared/mmc_wrapper.c
index c56a61e..01ef7e4 100644
--- a/platform/msm_shared/mmc_wrapper.c
+++ b/platform/msm_shared/mmc_wrapper.c
@@ -58,9 +58,9 @@
  */
 uint32_t mmc_write(uint64_t data_addr, uint32_t data_len, void *in)
 {
-	int val = 0;
+	uint32_t val = 0;
 	uint32_t write_size = SDHCI_ADMA_MAX_TRANS_SZ;
-	void *sptr = in;
+	uint8_t *sptr = (uint8_t *)in;
 	struct mmc_device *dev;
 
 	dev = target_mmc_device();
@@ -76,14 +76,22 @@
 	 * limitations
 	 */
 	while (data_len > write_size) {
-		val = mmc_sdhci_write(dev, sptr, (data_addr / MMC_BLK_SZ), (write_size / MMC_BLK_SZ));
+		val = mmc_sdhci_write(dev, (void *)sptr, (data_addr / MMC_BLK_SZ), (write_size / MMC_BLK_SZ));
+		if (val)
+		{
+			dprintf(CRITICAL, "Failed Writing block @ %x\n", (data_addr / MMC_BLK_SZ));
+			return val;
+		}
 		sptr += write_size;
 		data_addr += write_size;
 		data_len -= write_size;
 	}
 
 	if (data_len)
-		val = mmc_sdhci_write(dev, sptr, (data_addr / MMC_BLK_SZ), (data_len / MMC_BLK_SZ));
+		val = mmc_sdhci_write(dev, (void *)sptr, (data_addr / MMC_BLK_SZ), (data_len / MMC_BLK_SZ));
+
+	if (val)
+		dprintf(CRITICAL, "Failed Writing block @ %x\n", (data_addr / MMC_BLK_SZ));
 
 	return val;
 }
@@ -99,7 +107,7 @@
 	uint32_t ret = 0;
 	uint32_t read_size = SDHCI_ADMA_MAX_TRANS_SZ;
 	struct mmc_device *dev;
-	void *sptr = out;
+	uint8_t *sptr = (uint8_t *)out;
 
 	ASSERT(!(data_addr % MMC_BLK_SZ));
 	ASSERT(!(data_len % MMC_BLK_SZ));
@@ -112,14 +120,22 @@
 	 * limitations
 	 */
 	while (data_len > read_size) {
-		ret = mmc_sdhci_read(dev, sptr, (data_addr / MMC_BLK_SZ), (read_size / MMC_BLK_SZ));
+		ret = mmc_sdhci_read(dev, (void *)sptr, (data_addr / MMC_BLK_SZ), (read_size / MMC_BLK_SZ));
+		if (ret)
+		{
+			dprintf(CRITICAL, "Failed Reading block @ %x\n", (data_addr / MMC_BLK_SZ));
+			return ret;
+		}
 		sptr += read_size;
 		data_addr += read_size;
 		data_len -= read_size;
 	}
 
 	if (data_len)
-		ret = mmc_sdhci_read(dev, sptr, (data_addr / MMC_BLK_SZ), (data_len / MMC_BLK_SZ));
+		ret = mmc_sdhci_read(dev, (void *)sptr, (data_addr / MMC_BLK_SZ), (data_len / MMC_BLK_SZ));
+
+	if (ret)
+		dprintf(CRITICAL, "Failed Reading block @ %x\n", (data_addr / MMC_BLK_SZ));
 
 	return ret;
 }
@@ -128,14 +144,22 @@
  * Function: mmc erase card
  * Arg     : Block address & length
  * Return  : Returns 0
- * Flow    : This is dummy API for backward compatibility
- *           erase is not supported for sdhci
+ * Flow    : Erase the card from specified addr
  */
 uint32_t mmc_erase_card(uint64_t addr, uint64_t len)
 {
-	/* TODO: Right now with sdhci erase function
-	 * is not implemented, need to be added
-	 */
+	struct mmc_device *dev;
+
+	dev = target_mmc_device();
+
+	ASSERT(!(addr % MMC_BLK_SZ));
+	ASSERT(!(len % MMC_BLK_SZ));
+
+	if (mmc_sdhci_erase(dev, (addr / MMC_BLK_SZ), len))
+	{
+		dprintf(CRITICAL, "MMC erase failed\n");
+		return 1;
+	}
 	return 0;
 }
 
diff --git a/platform/msm_shared/sdhci.c b/platform/msm_shared/sdhci.c
index 221d2dd..21e3097 100644
--- a/platform/msm_shared/sdhci.c
+++ b/platform/msm_shared/sdhci.c
@@ -386,7 +386,7 @@
 static uint8_t sdhci_cmd_complete(struct sdhci_host *host, struct mmc_command *cmd)
 {
 	uint8_t i;
-	uint16_t retry = 0;
+	uint32_t retry = 0;
 	uint32_t int_status;
 
 	do {
@@ -485,14 +485,14 @@
 
 	if (len <= SDHCI_ADMA_DESC_LINE_SZ) {
 		/* Allocate only one descriptor */
-		sg_list = (struct desc_entry *) memalign(4, sizeof(struct desc_entry));
+		sg_list = (struct desc_entry *) memalign(lcm(4, CACHE_LINE), ROUNDUP(sizeof(struct desc_entry), CACHE_LINE));
 
 		if (!sg_list) {
 			dprintf(CRITICAL, "Error allocating memory\n");
 			ASSERT(0);
 		}
 
-		sg_list[0].addr = data;
+		sg_list[0].addr = (uint32_t)data;
 		sg_list[0].len = len;
 		sg_list[0].tran_att = SDHCI_ADMA_TRANS_VALID | SDHCI_ADMA_TRANS_DATA
 							  | SDHCI_ADMA_TRANS_END;
@@ -502,13 +502,14 @@
 		/* Calculate the number of entries in desc table */
 		sg_len = len / SDHCI_ADMA_DESC_LINE_SZ;
 		remain = len - (sg_len * SDHCI_ADMA_DESC_LINE_SZ);
-		/* Allocate sg_len + 1 entries */
+
+		/* Allocate sg_len + 1 entries if there are remaining bytes at the end */
 		if (remain)
 			sg_len++;
 
 		table_len = (sg_len * sizeof(struct desc_entry));
 
-		sg_list = (struct desc_entry *) memalign(4, table_len);
+		sg_list = (struct desc_entry *) memalign(lcm(4, CACHE_LINE), ROUNDUP(table_len, CACHE_LINE));
 
 		if (!sg_list) {
 			dprintf(CRITICAL, "Error allocating memory\n");
@@ -525,7 +526,7 @@
 		 * |_____________|_______________|_____________________|
 		 */
 		for (i = 0; i < (sg_len - 1); i++) {
-				sg_list[i].addr = data;
+				sg_list[i].addr = (uint32_t)data;
 				sg_list[i].len = SDHCI_ADMA_DESC_LINE_SZ;
 				sg_list[i].tran_att = SDHCI_ADMA_TRANS_VALID | SDHCI_ADMA_TRANS_DATA;
 				data += SDHCI_ADMA_DESC_LINE_SZ;
@@ -535,10 +536,10 @@
 			/* Fill the last entry of the table with Valid & End
 			 * attributes
 			 */
-			sg_list[sg_len - 1].addr = data;
+			sg_list[sg_len - 1].addr = (uint32_t)data;
 			sg_list[sg_len - 1].len = len;
-			sg_list[sg_len - 1].tran_att = SDHCI_ADMA_TRANS_VALID | SDHCI_ADMA_TRANS_DATA
-										   | SDHCI_ADMA_TRANS_END;
+			sg_list[sg_len - 1].tran_att = SDHCI_ADMA_TRANS_VALID | SDHCI_ADMA_TRANS_DATA |
+										   SDHCI_ADMA_TRANS_END;
 		}
 
 	arch_clean_invalidate_cache_range((addr_t)sg_list, table_len);
@@ -550,16 +551,15 @@
  * Function: sdhci adma transfer
  * Arg     : Host structure & command stucture
  * Return  : Pointer to desc table
- * Flow    : 1. Prepare data transfer properties
+ * Flow    : 1. Prepare descriptor table
  *           2. Write adma register
- *           3. Write transfer mode register
+ *           3. Write block size & block count register
  */
 static struct desc_entry *sdhci_adma_transfer(struct sdhci_host *host,
 											  struct mmc_command *cmd)
 {
 	uint32_t num_blks = 0;
 	uint32_t sz;
-	uint16_t trans_mode = 0;
 	void *data;
 	struct desc_entry *adma_addr;
 
@@ -583,35 +583,20 @@
 	/* Prepare adma descriptor table */
 	adma_addr = sdhci_prep_desc_table(data, sz);
 
+	/* Write adma address to adma register */
+	REG_WRITE32(host, (uint32_t) adma_addr, SDHCI_ADM_ADDR_REG);
+
 	/* Write the block size */
 	if (cmd->data.blk_sz)
 		REG_WRITE16(host, cmd->data.blk_sz, SDHCI_BLKSZ_REG);
 	else
 		REG_WRITE16(host, SDHCI_MMC_BLK_SZ, SDHCI_BLKSZ_REG);
 
-	/* Enalbe auto cmd 23 for multi block transfer */
-	if (num_blks > 1) {
-		trans_mode |= SDHCI_TRANS_MULTI | SDHCI_AUTO_CMD23_EN | SDHCI_BLK_CNT_EN;
-		REG_WRITE32(host, num_blks, SDHCI_ARG2_REG);
-	}
-
 	/*
 	 * Set block count in block count register
 	 */
-
 	REG_WRITE16(host, num_blks, SDHCI_BLK_CNT_REG);
 
-	if (cmd->trans_mode == SDHCI_MMC_READ)
-		trans_mode |= SDHCI_READ_MODE;
-
-	trans_mode |= SDHCI_DMA_EN;
-
-	/* Write adma address to adma register */
-	REG_WRITE32(host, (uint32_t) adma_addr, SDHCI_ADM_ADDR_REG);
-
-	/* Set transfer mode */
-	REG_WRITE16(host, trans_mode, SDHCI_TRANS_MODE_REG);
-
 	return adma_addr;
 }
 
@@ -628,6 +613,7 @@
 {
 	uint8_t retry = 0;
 	uint32_t resp_type = 0;
+	uint16_t trans_mode = 0;
 	uint16_t present_state;
 	uint32_t flags;
 	struct desc_entry *sg_list = NULL;
@@ -711,6 +697,25 @@
 	/* Write the argument 1 */
 	REG_WRITE32(host, cmd->argument, SDHCI_ARGUMENT_REG);
 
+	/* Set the Transfer mode */
+	if (cmd->data_present)
+	{
+		/* Enable DMA */
+		trans_mode |= SDHCI_DMA_EN;
+
+		if (cmd->trans_mode == SDHCI_MMC_READ)
+			trans_mode |= SDHCI_READ_MODE;
+
+		/* Enable auto cmd 23 for multi block transfer */
+		if (cmd->data.num_blocks > 1) {
+			trans_mode |= SDHCI_TRANS_MULTI | SDHCI_AUTO_CMD23_EN | SDHCI_BLK_CNT_EN;
+			REG_WRITE32(host, cmd->data.num_blocks, SDHCI_ARG2_REG);
+		}
+	}
+
+	/* Write to transfer mode register */
+	REG_WRITE16(host, trans_mode, SDHCI_TRANS_MODE_REG);
+
 	/* Write the command register */
 	REG_WRITE16(host, SDHCI_PREP_CMD(cmd->cmd_index, flags), SDHCI_CMD_REG);
 
diff --git a/project/msm8226.mk b/project/msm8226.mk
index 262abc8..a4315ad 100644
--- a/project/msm8226.mk
+++ b/project/msm8226.mk
@@ -11,11 +11,15 @@
 
 #DEFINES += WITH_DEBUG_DCC=1
 DEFINES += WITH_DEBUG_UART=1
+DEFINES += WITH_DEBUG_LOG_BUF=1
 #DEFINES += WITH_DEBUG_FBCON=1
 DEFINES += DEVICE_TREE=1
 #DEFINES += MMC_BOOT_BAM=1
 DEFINES += CRYPTO_BAM=1
 
+#Disable thumb mode
+ENABLE_THUMB := false
+
 ifeq ($(ENABLE_SDHCI_SUPPORT),1)
 DEFINES += MMC_SDHCI_SUPPORT=1
 endif
diff --git a/project/msm8974.mk b/project/msm8974.mk
index d84f39e..17f564b 100644
--- a/project/msm8974.mk
+++ b/project/msm8974.mk
@@ -18,7 +18,6 @@
 DEFINES += CRYPTO_BAM=1
 DEFINES += CRYPTO_REG_ACCESS=1
 DEFINES += ABOOT_IGNORE_BOOT_HEADER_ADDRS=1
-DEFINES += ASSERT_ON_TAMPER=1
 
 #Disable thumb mode
 ENABLE_THUMB := false
diff --git a/target/init.c b/target/init.c
index 937f136..8a9a9d0 100644
--- a/target/init.c
+++ b/target/init.c
@@ -24,6 +24,7 @@
 #include <debug.h>
 #include <target.h>
 #include <compiler.h>
+#include <dload_util.h>
 
 #define EXPAND(NAME) #NAME
 #define TARGET(NAME) EXPAND(NAME)
@@ -68,7 +69,7 @@
 {
 }
 
-__WEAK int set_download_mode(void)
+__WEAK int set_download_mode(enum dload_mode mode)
 {
 	return -1;
 }
@@ -122,3 +123,8 @@
 __WEAK void target_usb_stop(void)
 {
 }
+
+/* Default target specific target uninit */
+__WEAK void target_uninit(void)
+{
+}
diff --git a/target/msm8226/init.c b/target/msm8226/init.c
index ac648e8..e5b33fb 100644
--- a/target/msm8226/init.c
+++ b/target/msm8226/init.c
@@ -286,6 +286,11 @@
 	ulpi_write(ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT, ULPI_MISC_A_CLEAR);
 }
 
+void target_uninit(void)
+{
+	mmc_put_card_to_sleep(dev);
+}
+
 void target_usb_init(void)
 {
 	uint32_t val;
@@ -328,9 +333,10 @@
 	return _emmc_recovery_init();
 }
 
-int set_download_mode(void)
+int set_download_mode(enum dload_mode mode)
 {
-	dload_util_write_cookie(FORCE_DLOAD_MODE_ADDR);
+	dload_util_write_cookie(mode == NORMAL_DLOAD ?
+		DLOAD_MODE_ADDR : EMERGENCY_DLOAD_MODE_ADDR, mode);
 
 	return 0;
 }
diff --git a/target/msm8974/init.c b/target/msm8974/init.c
index 5a0057c..daa98b7 100644
--- a/target/msm8974/init.c
+++ b/target/msm8974/init.c
@@ -488,9 +488,10 @@
 	dprintf(CRITICAL, "Rebooting failed\n");
 }
 
-int set_download_mode(void)
+int set_download_mode(enum dload_mode mode)
 {
-	dload_util_write_cookie(FORCE_DLOAD_MODE_ADDR_V2);
+	dload_util_write_cookie(mode == NORMAL_DLOAD ?
+		DLOAD_MODE_ADDR_V2 : EMERGENCY_DLOAD_MODE_ADDR_V2, mode);
 
 	return 0;
 }
diff --git a/target/msm8974/target_display.c b/target/msm8974/target_display.c
index 883cead..cf0f6cc 100644
--- a/target/msm8974/target_display.c
+++ b/target/msm8974/target_display.c
@@ -46,16 +46,18 @@
 extern int mdss_dsi_uniphy_pll_config(void);
 extern int mdss_sharp_dsi_uniphy_pll_config(void);
 
+static struct pm8x41_wled_data wled_ctrl = {
+	.mod_scheme      = 0xC3,
+	.led1_brightness = (0x0F << 8) | 0xEF,
+	.led2_brightness = (0x0F << 8) | 0xEF,
+	.led3_brightness = (0x0F << 8) | 0xEF,
+	.max_duty_cycle  = 0x01,
+	.ovp = 0x2,
+	.full_current_scale = 0x19
+};
+
 static int msm8974_backlight_on()
 {
-	static struct pm8x41_wled_data wled_ctrl = {
-		.mod_scheme      = 0xC3,
-		.led1_brightness = (0x0F << 8) | 0xEF,
-		.led2_brightness = (0x0F << 8) | 0xEF,
-		.led3_brightness = (0x0F << 8) | 0xEF,
-		.max_duty_cycle  = 0x01,
-	};
-
 	pm8x41_wled_config(&wled_ctrl);
 	pm8x41_wled_sink_control(1);
 	pm8x41_wled_iled_sync_control(1);
@@ -128,6 +130,11 @@
 
 static int msm8974_mipi_panel_power(uint8_t enable)
 {
+
+	struct pm8x41_ldo ldo2  = LDO(PM8x41_LDO2, NLDO_TYPE);
+	struct pm8x41_ldo ldo12 = LDO(PM8x41_LDO12, PLDO_TYPE);
+	struct pm8x41_ldo ldo22 = LDO(PM8x41_LDO22, PLDO_TYPE);
+
 	if (enable) {
 
 		/* Enable backlight */
@@ -135,18 +142,18 @@
 
 		/* Turn on LDO8 for lcd1 mipi vdd */
 		dprintf(SPEW, " Setting LDO22\n");
-		pm8x41_ldo_set_voltage("LDO22", 3000000);
-		pm8x41_ldo_control("LDO22", enable);
+		pm8x41_ldo_set_voltage(&ldo22, 3000000);
+		pm8x41_ldo_control(&ldo22, enable);
 
 		dprintf(SPEW, " Setting LDO12\n");
 		/* Turn on LDO23 for lcd1 mipi vddio */
-		pm8x41_ldo_set_voltage("LDO12", 1800000);
-		pm8x41_ldo_control("LDO12", enable);
+		pm8x41_ldo_set_voltage(&ldo12, 1800000);
+		pm8x41_ldo_control(&ldo12, enable);
 
 		dprintf(SPEW, " Setting LDO2\n");
 		/* Turn on LDO2 for vdda_mipi_dsi */
-		pm8x41_ldo_set_voltage("LDO2", 1200000);
-		pm8x41_ldo_control("LDO2", enable);
+		pm8x41_ldo_set_voltage(&ldo2, 1200000);
+		pm8x41_ldo_control(&ldo2, enable);
 
 		dprintf(SPEW, " Panel Reset \n");
 		/* Panel Reset */
@@ -155,8 +162,8 @@
 	} else {
 		msm8974_mdss_mipi_panel_reset(enable);
 		pm8x41_wled_enable(enable);
-		pm8x41_ldo_control("LDO2", enable);
-		pm8x41_ldo_control("LDO22", enable);
+		pm8x41_ldo_control(&ldo2, enable);
+		pm8x41_ldo_control(&ldo22, enable);
 
 	}
 
@@ -187,6 +194,8 @@
 		break;
 	case HW_PLATFORM_DRAGON:
 		mipi_sharp_video_qhd_init(&(panel.panel_info));
+		wled_ctrl.ovp = 0x1; /* 32V */
+		wled_ctrl.full_current_scale = 0x14; /* 20mA */
 		panel.clk_func = msm8974_mdss_sharp_dsi_panel_clock;
 		panel.power_func = msm8974_mipi_panel_power;
 		panel.fb.base = MIPI_FB_ADDR;