Merge "platform: msm_shared: Remove references to thulium"
diff --git a/AndroidBoot.mk b/AndroidBoot.mk
index b158dec..1b336e3 100644
--- a/AndroidBoot.mk
+++ b/AndroidBoot.mk
@@ -20,7 +20,7 @@
 ifeq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),true)
   VERIFIED_BOOT := VERIFIED_BOOT=1
 else
-  VERIFIED_BOOT := VERIFEID_BOOT=0
+  VERIFIED_BOOT := VERIFIED_BOOT=0
 endif
 
 ifneq ($(TARGET_BUILD_VARIANT),user)
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 3b8aead..5451150 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -759,18 +759,6 @@
 	set_tamper_flag(device.is_tampered);
 #endif
 
-	if(device.is_tampered)
-	{
-		write_device_info_mmc(&device);
-	#ifdef TZ_TAMPER_FUSE
-		set_tamper_fuse_cmd();
-	#endif
-	#ifdef ASSERT_ON_TAMPER
-		dprintf(CRITICAL, "Device is tampered. Asserting..\n");
-		ASSERT(0);
-	#endif
-	}
-
 #if VERIFIED_BOOT
 	if(boot_verify_get_state() == RED)
 	{
@@ -788,6 +776,19 @@
 		}
 	}
 #endif
+
+	if(device.is_tampered)
+	{
+		write_device_info_mmc(&device);
+	#ifdef TZ_TAMPER_FUSE
+		set_tamper_fuse_cmd();
+	#endif
+	#ifdef ASSERT_ON_TAMPER
+		dprintf(CRITICAL, "Device is tampered. Asserting..\n");
+		ASSERT(0);
+	#endif
+	}
+
 }
 
 static bool check_format_bit()
@@ -2335,6 +2336,30 @@
 	return;
 }
 
+void cmd_updatevol(const char *vol_name, void *data, unsigned sz)
+{
+	struct ptentry *sys_ptn;
+	struct ptable *ptable;
+
+	ptable = flash_get_ptable();
+	if (ptable == NULL) {
+		fastboot_fail("partition table doesn't exist");
+		return;
+	}
+
+	sys_ptn = ptable_find(ptable, "system");
+	if (sys_ptn == NULL) {
+		fastboot_fail("system partition not found");
+		return;
+	}
+
+	sz = ROUND_TO_PAGE(sz, page_mask);
+	if (update_ubi_vol(sys_ptn, vol_name, data, sz))
+		fastboot_fail("update_ubi_vol failed");
+	else
+		fastboot_okay("");
+}
+
 void cmd_flash_nand(const char *arg, void *data, unsigned sz)
 {
 	struct ptentry *ptn;
@@ -2349,7 +2374,9 @@
 
 	ptn = ptable_find(ptable, arg);
 	if (ptn == NULL) {
-		fastboot_fail("unknown partition name");
+		dprintf(INFO, "unknown partition name (%s). Trying updatevol\n",
+				arg);
+		cmd_updatevol(arg, data, sz);
 		return;
 	}
 
diff --git a/include/dev/flash-ubi.h b/include/dev/flash-ubi.h
index 50577cc..a8bf819 100644
--- a/include/dev/flash-ubi.h
+++ b/include/dev/flash-ubi.h
@@ -77,6 +77,8 @@
 
 /* Erase counter header magic number (ASCII "UBI#") */
 #define UBI_EC_HDR_MAGIC  0x55424923
+/* Volume identifier header magic number (ASCII "UBI!") */
+#define UBI_VID_HDR_MAGIC 0x55424921
 
 #define UBI_MAGIC      "UBI#"
 #define UBI_MAGIC_SIZE 0x04
@@ -129,30 +131,85 @@
 #define UBI_MAX_VOLUMES 128
 #define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
 #define UBI_LAYOUT_VOLUME_ID     UBI_INTERNAL_VOL_START
+#define UBI_VID_DYNAMIC 1
+#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC
 #define UBI_FM_SB_VOLUME_ID	(UBI_INTERNAL_VOL_START + 1)
 
+/* A record in the UBI volume table. */
+struct __attribute__ ((packed)) ubi_vtbl_record {
+	uint32_t  reserved_pebs;
+	uint32_t  alignment;
+	uint32_t  data_pad;
+	uint8_t    vol_type;
+	uint8_t    upd_marker;
+	uint16_t  name_len;
+#define UBI_VOL_NAME_MAX 127
+	uint8_t    name[UBI_VOL_NAME_MAX+1];
+	uint8_t    flags;
+	uint8_t    padding[23];
+	uint32_t  crc;
+};
+#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(uint32_t))
+
+/* PEB status */
+enum {
+	UBI_UNKNOWN = 0,
+	UBI_BAD_PEB,
+	UBI_FREE_PEB,
+	UBI_USED_PEB,
+	UBI_EMPTY_PEB
+};
+
+/**
+ * struct peb_info - In RAM info on a PEB
+ * @ec: erase counter
+ * @status: status of this PEB: UBI_BAD_PEB/USED/FREE/EMPTY
+ * @volume: if status = UBI_USED_PEB this is the volume
+ * 		ID this PEB belongs to -1 for any other status
+ */
+struct peb_info {
+	uint64_t ec;
+	int status;
+	int volume;
+};
+
 /**
  * struct ubi_scan_info - UBI scanning information.
- * @ec: erase counters or eraseblock status for all eraseblocks
+ * @pebs_data: info on all of partition PEBs
  * @mean_ec: mean erase counter
+ * @vtbl_peb1: number of the first PEB holding the volume table
+ * 			 (relative to the beginning of the partition)
+ * @vtbl_peb1: number of the second PEB holding the volume table
+ * 			 (relative to the beginning of the partition)
  * @bad_cnt: count of bad eraseblocks
- * @good_cnt: count of non-bad eraseblocks
  * @empty_cnt: count of empty eraseblocks
+ * @free_cnt: count of free eraseblocks
+ * @used_cnt: count of used eraseblocks
+ * @fastmap_sb: PEB number holding FM superblock. If FM is not present: -1
  * @vid_hdr_offs: volume ID header offset from the found EC headers (%-1 means
  *                undefined)
  * @data_offs: data offset from the found EC headers (%-1 means undefined)
  * @image_seq: image sequence
+ * @read_image_seq: image sequence read from NAND while scanning
  */
 struct ubi_scan_info {
-	uint64_t *ec;
+	struct peb_info *pebs_data;
 	uint64_t mean_ec;
+	int vtbl_peb1;
+	int vtbl_peb2;
 	int bad_cnt;
-	int good_cnt;
 	int empty_cnt;
+	int free_cnt;
+	int used_cnt;
+	int fastmap_sb;
 	unsigned vid_hdr_offs;
 	unsigned data_offs;
 	uint32_t  image_seq;
+	uint32_t  read_image_seq;
 };
 
 int flash_ubi_img(struct ptentry *ptn, void *data, unsigned size);
+int update_ubi_vol(struct ptentry *ptn, const char* vol_name,
+				void *data, unsigned size);
 #endif
diff --git a/include/dev/udc.h b/include/dev/udc.h
index 42ced0e..31d9755 100644
--- a/include/dev/udc.h
+++ b/include/dev/udc.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2009, Google Inc.
  * All rights reserved.
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -50,6 +50,8 @@
 
 #define UDC_TYPE_BULK_IN	1
 #define UDC_TYPE_BULK_OUT	2
+#define UDC_TYPE_INTR_IN	3
+#define UDC_TYPE_INTR_OUT	4
 
 struct udc_endpoint *udc_endpoint_alloc(unsigned type, unsigned maxpkt);
 void udc_endpoint_free(struct udc_endpoint *ept);
diff --git a/platform/msm8952/acpuclock.c b/platform/msm8952/acpuclock.c
index ffb8b92..ff25ac0 100644
--- a/platform/msm8952/acpuclock.c
+++ b/platform/msm8952/acpuclock.c
@@ -38,24 +38,144 @@
 
 void hsusb_clock_init(void)
 {
+	int ret;
+	struct clk *iclk, *cclk;
 
+	ret = clk_get_set_enable("usb_iface_clk", 0, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set usb_iface_clk ret = %d\n", ret);
+		ASSERT(0);
+	}
+
+	ret = clk_get_set_enable("usb_core_clk", 80000000, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set usb_core_clk ret = %d\n", ret);
+		ASSERT(0);
+	}
+
+	mdelay(20);
+
+	iclk = clk_get("usb_iface_clk");
+	cclk = clk_get("usb_core_clk");
+
+	clk_disable(iclk);
+	clk_disable(cclk);
+
+	mdelay(20);
+
+	/* Start the block reset for usb */
+	writel(1, USB_HS_BCR);
+
+	mdelay(20);
+
+	/* Take usb block out of reset */
+	writel(0, USB_HS_BCR);
+
+	mdelay(20);
+
+	ret = clk_enable(iclk);
+
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set usb_iface_clk after async ret = %d\n", ret);
+		ASSERT(0);
+	}
+
+	ret = clk_enable(cclk);
+
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set usb_iface_clk after async ret = %d\n", ret);
+		ASSERT(0);
+	}
 }
 
 void clock_init_mmc(uint32_t interface)
 {
+	char clk_name[64];
+	int ret;
 
+	snprintf(clk_name, sizeof(clk_name), "sdc%u_iface_clk", interface);
+
+	/* enable interface clock */
+	ret = clk_get_set_enable(clk_name, 0, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set sdc1_iface_clk ret = %d\n", ret);
+		ASSERT(0);
+	}
 }
 
 /* Configure MMC clock */
 void clock_config_mmc(uint32_t interface, uint32_t freq)
 {
-	mmc_boot_mci_clk_enable();
+	int ret = 1;
+	char clk_name[64];
+
+	snprintf(clk_name, sizeof(clk_name), "sdc%u_core_clk", interface);
+
+	if(freq == MMC_CLK_400KHZ)
+	{
+		ret = clk_get_set_enable(clk_name, 400000, 1);
+	}
+	else if(freq == MMC_CLK_50MHZ)
+	{
+		ret = clk_get_set_enable(clk_name, 50000000, 1);
+	}
+	else if(freq == MMC_CLK_177MHZ)
+	{
+		ret = clk_get_set_enable(clk_name, 177770000, 1);
+	}
+	else if(freq == MMC_CLK_192MHZ)
+	{
+		ret = clk_get_set_enable(clk_name, 192000000, 1);
+	}
+	else if(freq == MMC_CLK_200MHZ)
+	{
+		ret = clk_get_set_enable(clk_name, 200000000, 1);
+	}
+	else if(freq == MMC_CLK_400MHZ)
+	{
+		ret = clk_get_set_enable(clk_name, 384000000, 1);
+	}
+	else
+	{
+		dprintf(CRITICAL, "sdc frequency (%u) is not supported\n", freq);
+		ASSERT(0);
+	}
+
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set %s ret = %d\n", clk_name, ret);
+		ASSERT(0);
+	}
 }
 
 /* Configure UART clock based on the UART block id*/
 void clock_config_uart_dm(uint8_t id)
 {
+	int ret;
+	char iclk[64];
+	char cclk[64];
 
+	snprintf(iclk, sizeof(iclk), "uart%u_iface_clk", id);
+	snprintf(cclk, sizeof(cclk), "uart%u_core_clk", id);
+
+	ret = clk_get_set_enable(iclk, 0, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set %s ret = %d\n", iclk, ret);
+		ASSERT(0);
+	}
+
+	ret = clk_get_set_enable(cclk, 7372800, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set %s ret = %d\n", cclk, ret);
+		ASSERT(0);
+	}
 }
 
 /* Function to asynchronously reset CE.
@@ -63,16 +183,91 @@
  */
 static void ce_async_reset(uint8_t instance)
 {
+	/* Start the block reset for CE */
+	writel(1, GCC_CRYPTO_BCR);
 
+	udelay(2);
+
+	/* Take CE block out of reset */
+	writel(0, GCC_CRYPTO_BCR);
+
+	udelay(2);
 }
 
 void clock_ce_enable(uint8_t instance)
 {
+	int ret;
+	char clk_name[64];
+
+	snprintf(clk_name, sizeof(clk_name), "ce%u_src_clk", instance);
+	ret = clk_get_set_enable(clk_name, 160000000, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set ce%u_src_clk ret = %d\n", instance, ret);
+		ASSERT(0);
+	}
+
+	snprintf(clk_name, sizeof(clk_name), "ce%u_core_clk", instance);
+	ret = clk_get_set_enable(clk_name, 0, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set ce%u_core_clk ret = %d\n", instance, ret);
+		ASSERT(0);
+	}
+
+	snprintf(clk_name, sizeof(clk_name), "ce%u_ahb_clk", instance);
+	ret = clk_get_set_enable(clk_name, 0, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set ce%u_ahb_clk ret = %d\n", instance, ret);
+		ASSERT(0);
+	}
+
+	snprintf(clk_name, sizeof(clk_name), "ce%u_axi_clk", instance);
+	ret = clk_get_set_enable(clk_name, 0, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set ce%u_axi_clk ret = %d\n", instance, ret);
+		ASSERT(0);
+	}
+
+	/* Wait for 48 * #pipes cycles.
+	 * This is necessary as immediately after an access control reset (boot up)
+	 * or a debug re-enable, the Crypto core sequentially clears its internal
+	 * pipe key storage memory. If pipe key initialization writes are attempted
+	 * during this time, they may be overwritten by the internal clearing logic.
+	 */
+	udelay(1);
 
 }
 
 void clock_ce_disable(uint8_t instance)
 {
+	struct clk *ahb_clk;
+	struct clk *cclk;
+	struct clk *axi_clk;
+	struct clk *src_clk;
+	char clk_name[64];
+
+	snprintf(clk_name, sizeof(clk_name), "ce%u_src_clk", instance);
+	src_clk = clk_get(clk_name);
+
+	snprintf(clk_name, sizeof(clk_name), "ce%u_ahb_clk", instance);
+	ahb_clk = clk_get(clk_name);
+
+	snprintf(clk_name, sizeof(clk_name), "ce%u_axi_clk", instance);
+	axi_clk = clk_get(clk_name);
+
+	snprintf(clk_name, sizeof(clk_name), "ce%u_core_clk", instance);
+	cclk    = clk_get(clk_name);
+
+	clk_disable(ahb_clk);
+	clk_disable(axi_clk);
+	clk_disable(cclk);
+	clk_disable(src_clk);
+
+	/* Some delay for the clocks to stabalize. */
+	udelay(1);
 
 }
 
diff --git a/platform/msm8952/include/platform/iomap.h b/platform/msm8952/include/platform/iomap.h
index ac40933..f4712d7 100644
--- a/platform/msm8952/include/platform/iomap.h
+++ b/platform/msm8952/include/platform/iomap.h
@@ -62,6 +62,7 @@
 #define MSM_SDC1_BASE                      (PERIPH_SS_BASE + 0x00024000)
 #define MSM_SDC2_BASE                      (PERIPH_SS_BASE + 0x00064000)
 
+/* UART */
 #define BLSP1_UART0_BASE                   (PERIPH_SS_BASE + 0x000AF000)
 #define BLSP1_UART1_BASE                   (PERIPH_SS_BASE + 0x000B0000)
 #define MSM_USB_BASE                       (PERIPH_SS_BASE + 0x000DB000)
@@ -84,12 +85,18 @@
 /* CRYPTO ENGINE */
 #define  MSM_CE1_BASE                      0x073A000
 #define  MSM_CE1_BAM_BASE                  0x0704000
-
+#define  GCC_CRYPTO_BCR                    (CLK_CTL_BASE + 0x16000)
+#define  GCC_CRYPTO_CMD_RCGR               (CLK_CTL_BASE + 0x16004)
+#define  GCC_CRYPTO_CFG_RCGR               (CLK_CTL_BASE + 0x16008)
+#define  GCC_CRYPTO_CBCR                   (CLK_CTL_BASE + 0x1601C)
+#define  GCC_CRYPTO_AXI_CBCR               (CLK_CTL_BASE + 0x16020)
+#define  GCC_CRYPTO_AHB_CBCR               (CLK_CTL_BASE + 0x16024)
 
 /* GPLL */
 #define GPLL0_STATUS                       (CLK_CTL_BASE + 0x2101C)
 #define APCS_GPLL_ENA_VOTE                 (CLK_CTL_BASE + 0x45000)
 #define APCS_CLOCK_BRANCH_ENA_VOTE         (CLK_CTL_BASE + 0x45004)
+#define GPLL4_MODE                         (CLK_CTL_BASE + 0x24000)
 
 /* SDCC */
 #define SDC1_HDRV_PULL_CTL                 (TLMM_BASE_ADDR + 0x10A000)
@@ -102,6 +109,25 @@
 #define SDCC1_N                            (CLK_CTL_BASE + 0x42010) /* n */
 #define SDCC1_D                            (CLK_CTL_BASE + 0x42014) /* d */
 
+/* SDHCI */
+#define MSM_SDC1_SDHCI_BASE                (PERIPH_SS_BASE + 0x00024900)
+#define MSM_SDC2_SDHCI_BASE                (PERIPH_SS_BASE + 0x00064900)
+
+#define SDCC_MCI_HC_MODE                   (0x00000078)
+#define SDCC_HC_PWRCTL_STATUS_REG          (0x000000DC)
+#define SDCC_HC_PWRCTL_MASK_REG            (0x000000E0)
+#define SDCC_HC_PWRCTL_CLEAR_REG           (0x000000E4)
+#define SDCC_HC_PWRCTL_CTL_REG             (0x000000E8)
+
+#define SDCC2_BCR                          (CLK_CTL_BASE + 0x43000) /* block reset */
+#define SDCC2_APPS_CBCR                    (CLK_CTL_BASE + 0x43018) /* branch control */
+#define SDCC2_AHB_CBCR                     (CLK_CTL_BASE + 0x4301C)
+#define SDCC2_CMD_RCGR                     (CLK_CTL_BASE + 0x43004) /* cmd */
+#define SDCC2_CFG_RCGR                     (CLK_CTL_BASE + 0x43008) /* cfg */
+#define SDCC2_M                            (CLK_CTL_BASE + 0x4300C) /* m */
+#define SDCC2_N                            (CLK_CTL_BASE + 0x43010) /* n */
+#define SDCC2_D                            (CLK_CTL_BASE + 0x43014) /* d */
+
 /* UART */
 #define BLSP1_AHB_CBCR                     (CLK_CTL_BASE + 0x1008)
 #define BLSP1_UART2_APPS_CBCR              (CLK_CTL_BASE + 0x302C)
diff --git a/platform/msm8952/include/platform/irqs.h b/platform/msm8952/include/platform/irqs.h
index 31da373..810f113 100644
--- a/platform/msm8952/include/platform/irqs.h
+++ b/platform/msm8952/include/platform/irqs.h
@@ -46,6 +46,8 @@
 
 #define USB1_HS_BAM_IRQ                        (GIC_SPI_START + 135)
 #define USB1_HS_IRQ                            (GIC_SPI_START + 134)
+#define SDCC1_PWRCTL_IRQ                       (GIC_SPI_START + 138)
+#define SDCC2_PWRCTL_IRQ                       (GIC_SPI_START + 221)
 
 /* Retrofit universal macro names */
 #define INT_USB_HS                             USB1_HS_IRQ
diff --git a/platform/msm8952/msm8952-clock.c b/platform/msm8952/msm8952-clock.c
index ed39611..f464cc8 100644
--- a/platform/msm8952/msm8952-clock.c
+++ b/platform/msm8952/msm8952-clock.c
@@ -111,6 +111,21 @@
 	},
 };
 
+static struct pll_vote_clk gpll4_clk_src =
+{
+	.en_reg       = (void *) APCS_GPLL_ENA_VOTE,
+	.en_mask      = BIT(5),
+	.status_reg   = (void *) GPLL4_MODE,
+	.status_mask  = BIT(30),
+	.parent       = &cxo_clk_src.c,
+
+	.c = {
+		.rate     = 1152000000,
+		.dbg_name = "gpll4_clk_src",
+		.ops      = &clk_ops_pll_vote,
+	},
+};
+
 /* SDCC Clocks */
 static struct clk_freq_tbl ftbl_gcc_sdcc1_apps_clk[] =
 {
@@ -121,8 +136,8 @@
 	F( 50000000,  gpll0,  16,   0,   0),
 	F(100000000,  gpll0,   8,   0,   0),
 	F(177770000,  gpll0, 4.5,   0,   0),
-	F(200000000,  gpll0,   4,   0,   0),
-	F(400000000,  gpll4,   3,   0,   0),
+	F(192000000,  gpll0,   6,   0,   0),
+	F(384000000,  gpll4,   3,   0,   0),
 	F_END
 };
 
@@ -135,7 +150,7 @@
 	.d_reg        = (uint32_t *) SDCC1_D,
 
 	.set_rate     = clock_lib2_rcg_set_rate_mnd,
-	.freq_tbl     = ftbl_gcc_sdcc1_2_apps_clk,
+	.freq_tbl     = ftbl_gcc_sdcc1_apps_clk,
 	.current_freq = &rcg_dummy_freq,
 
 	.c = {
diff --git a/platform/msm8952/platform.c b/platform/msm8952/platform.c
index 4648638..1ee7cdc 100644
--- a/platform/msm8952/platform.c
+++ b/platform/msm8952/platform.c
@@ -29,12 +29,16 @@
 #include <debug.h>
 #include <reg.h>
 #include <platform/iomap.h>
+#include <platform/irqs.h>
+#include <platform/clock.h>
 #include <qgic.h>
 #include <qtimer.h>
 #include <mmu.h>
 #include <arch/arm/mmu.h>
 #include <smem.h>
 #include <board.h>
+#include <boot_stats.h>
+#include <platform.h>
 
 #define MSM_IOMAP_SIZE ((MSM_IOMAP_END - MSM_IOMAP_BASE)/MB)
 #define APPS_SS_SIZE   ((APPS_SS_END - APPS_SS_BASE)/MB)
@@ -66,6 +70,7 @@
 void platform_early_init(void)
 {
 	board_init();
+	platform_clock_init();
 	qgic_init();
 	qtimer_init();
 	scm_init();
diff --git a/platform/msm8952/rules.mk b/platform/msm8952/rules.mk
index ebae71e..a337b97 100644
--- a/platform/msm8952/rules.mk
+++ b/platform/msm8952/rules.mk
@@ -12,13 +12,14 @@
 
 DEFINES += PERIPH_BLK_BLSP=1
 DEFINES += WITH_CPU_EARLY_INIT=0 WITH_CPU_WARM_BOOT=0 \
-           MMC_SLOT=$(MMC_SLOT)
+	MMC_SLOT=$(MMC_SLOT) SSD_ENABLE
 
 INCLUDES += -I$(LOCAL_DIR)/include -I$(LK_TOP_DIR)/platform/msm_shared/include
 
 OBJS += \
        $(LOCAL_DIR)/platform.o \
        $(LOCAL_DIR)/acpuclock.o \
+       $(LOCAL_DIR)/msm8952-clock.o \
        $(LOCAL_DIR)/gpio.o
 
 LINKER_SCRIPT += $(BUILDDIR)/system-onesegment.ld
diff --git a/platform/msm8996/platform.c b/platform/msm8996/platform.c
index a1c2dde..a82357b 100644
--- a/platform/msm8996/platform.c
+++ b/platform/msm8996/platform.c
@@ -142,3 +142,8 @@
 	return readl(USB3_PHY_REVISION_ID3) << 24 | readl(USB3_PHY_REVISION_ID2) << 16 |
 		   readl(USB3_PHY_REVISION_ID1) << 8 | readl(USB3_PHY_REVISION_ID0);
 }
+
+uint32_t platform_get_max_periph()
+{
+	return 256;
+}
diff --git a/platform/msm_shared/flash-ubi.c b/platform/msm_shared/flash-ubi.c
index 0051a3a..9b9dd51 100644
--- a/platform/msm_shared/flash-ubi.c
+++ b/platform/msm_shared/flash-ubi.c
@@ -118,6 +118,30 @@
 }
 
 /**
+ * calc_data_len - calculate how much real data is stored in the buffer
+ * @page_size: min I/O of the device
+ * @buf: a buffer with the contents of the physical eraseblock
+ * @len: the buffer length
+ *
+ * This function calculates how much "real data" is stored in @buf and
+ * returns the length (in number of pages). Continuous 0xFF bytes at the end
+ * of the buffer are not considered as "real data".
+ */
+static int calc_data_len(int page_size, const void *buf, int len)
+{
+	int i;
+
+	for (i = len - 1; i >= 0; i--)
+		if (((const uint8_t *)buf)[i] != 0xFF)
+			break;
+
+	/* The resulting length must be aligned to the minimum flash I/O size */
+	len = i + 1;
+	len = (len + page_size - 1) / page_size;
+	return len;
+}
+
+/**
  * read_ec_hdr - read and check an erase counter header.
  * @peb: number of the physical erase block to read the header for
  * @ec_hdr: a &struct ubi_ec_hdr object where to store the read erase counter
@@ -209,6 +233,141 @@
 }
 
 /**
+ * read_vid_hdr - read and check an Volume identifier header.
+ * @peb: number of the physical erase block to read the header for
+ * @vid_hdr: a &struct ubi_vid_hdr object where to store the read header
+ * @vid_hdr_offset: offset of the VID header from the beginning of the PEB
+ * 			 (in bytes)
+ *
+ * This function reads the volume identifier header from physical
+ * eraseblock @peb and stores it in @vid_hdr. This function also checks the
+ * validity of the read header.
+ *
+ * Return codes:
+ * -1 - in case of error
+ *  0 - on success
+ *  1 - if the PEB is free (no VID hdr)
+ */
+static int read_vid_hdr(uint32_t peb, struct ubi_vid_hdr *vid_hdr,
+		int vid_hdr_offset)
+{
+	unsigned char *spare, *tmp_buf;
+	int ret = -1;
+	uint32_t crc, magic;
+	int page_size = flash_page_size();
+	int num_pages_per_blk = flash_block_size()/page_size;
+
+	spare = (unsigned char *)malloc(flash_spare_size());
+	if (!spare)
+	{
+		dprintf(CRITICAL, "read_vid_hdr: Mem allocation failed\n");
+		return ret;
+	}
+
+	tmp_buf = (unsigned char *)malloc(page_size);
+	if (!tmp_buf)
+	{
+		dprintf(CRITICAL, "read_vid_hdr: Mem allocation failed\n");
+		goto out_tmp_buf;
+	}
+
+	if (qpic_nand_block_isbad(peb * num_pages_per_blk)) {
+		dprintf(CRITICAL, "read_vid_hdr: Bad block @ %d\n", peb);
+		goto out;
+	}
+
+	if (qpic_nand_read(peb * num_pages_per_blk + vid_hdr_offset/page_size,
+			1, tmp_buf, spare)) {
+		dprintf(CRITICAL, "read_vid_hdr: Read %d failed \n", peb);
+		goto out;
+	}
+	memcpy(vid_hdr, tmp_buf, UBI_VID_HDR_SIZE);
+
+	if (check_pattern((void *)vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
+		ret = 1;
+		goto out;
+	}
+
+	magic = BE32(vid_hdr->magic);
+	if (magic != UBI_VID_HDR_MAGIC) {
+		dprintf(CRITICAL,
+				"read_vid_hdr: Wrong magic at peb-%d Expected: %d, received %d\n",
+				peb, UBI_VID_HDR_MAGIC, BE32(vid_hdr->magic));
+		goto out;
+	}
+
+	crc = mtd_crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
+	if (BE32(vid_hdr->hdr_crc) != crc) {
+		dprintf(CRITICAL,
+			"read_vid_hdr: Wrong crc at peb-%d: calculated %d, received %d\n",
+			peb,crc,  BE32(vid_hdr->hdr_crc));
+		goto out;
+	}
+
+	ret = 0;
+out:
+	free(tmp_buf);
+out_tmp_buf:
+	free(spare);
+	return ret;
+}
+
+/**
+ * read_leb_data - read data section of the PEB (LEB).
+ * @peb: number of the physical erase block to read the data for
+ * @leb_data: a buffer where to store the read data at
+ * @leb_size: LEB size
+ * @data_offset: offset of the data from the beginning of the PEB
+ * 			 (in bytes)
+ *
+ * Return codes:
+ * -1 - in case of error
+ *  0 - on success
+ */
+static int read_leb_data(uint32_t peb, void *leb_data,
+		int leb_size, int data_offset)
+{
+	unsigned char *spare, *tmp_buf;
+	int ret = -1;
+	int page_size = flash_page_size();
+	int block_size = flash_block_size();
+	int num_pages_per_blk = block_size/page_size;
+
+	spare = (unsigned char *)malloc(flash_spare_size());
+	if (!spare)
+	{
+		dprintf(CRITICAL, "read_leb_data: Mem allocation failed\n");
+		return ret;
+	}
+
+	tmp_buf = (unsigned char *)malloc(leb_size);
+	if (!tmp_buf)
+	{
+		dprintf(CRITICAL, "read_leb_data: Mem allocation failed\n");
+		goto out_tmp_buf;
+	}
+
+	if (qpic_nand_block_isbad(peb * num_pages_per_blk)) {
+		dprintf(CRITICAL, "read_leb_data: Bad block @ %d\n", peb);
+		goto out;
+	}
+
+	if (qpic_nand_read(peb * num_pages_per_blk + data_offset/page_size,
+			leb_size/page_size, tmp_buf, spare)) {
+		dprintf(CRITICAL, "read_leb_data: Read %d failed \n", peb);
+		goto out;
+	}
+	memcpy(leb_data, tmp_buf, leb_size);
+
+	ret = 0;
+out:
+	free(tmp_buf);
+out_tmp_buf:
+	free(spare);
+	return ret;
+}
+
+/**
  * write_ec_header() - Write provided ec_header for given PEB
  * @peb: number of the physical erase block to write the header to
  * @new_ech: the ec_header to write
@@ -247,6 +406,97 @@
 }
 
 /**
+ * write_vid_header() - Write provided vid_header for given PEB
+ * @peb: number of the physical erase block to write the header to
+ * @new_vidh: the vid_header to write
+ * @offset: vid_hdr offset in bytes from the beginning of the PEB
+ *
+ * Return codes:
+ * -1 - in case of error
+ *  0 - on success
+ */
+static int write_vid_header(uint32_t peb,
+		struct ubi_vid_hdr *new_vidh, int offset)
+{
+	unsigned page_size = flash_page_size();
+	int num_pages_per_blk = flash_block_size()/page_size;
+	unsigned char *buf;
+	int ret = 0;
+
+	buf = malloc(sizeof(uint8_t) * page_size);
+	if (!buf) {
+		dprintf(CRITICAL, "write_vid_header: Mem allocation failed\n");
+		return -1;
+	}
+
+	memset(buf, 0, page_size);
+	ASSERT(page_size > sizeof(*new_vidh));
+	memcpy(buf, new_vidh, UBI_VID_HDR_SIZE);
+	ret = qpic_nand_write(peb * num_pages_per_blk + offset/page_size,
+			1, buf, 0);
+	if (ret) {
+		dprintf(CRITICAL,
+			"write_vid_header: qpic_nand_write failed with %d\n", ret);
+		ret = -1;
+		goto out;
+	}
+
+out:
+	free(buf);
+	return ret;
+}
+
+/**
+ * write_leb_data - write data section of the PEB (LEB).
+ * @peb: number of the physical erase block to write the data for
+ * @leb_data: a data buffer to write
+ * @size: data size
+ * @data_offset: offset of the data from the beginning of the PEB
+ * 			 (in bytes)
+ *
+ * Return codes:
+ * -1 - in case of error
+ *  0 - on success
+ */
+static int write_leb_data(uint32_t peb, void *data,
+		int size, int data_offset)
+{
+	unsigned char *tmp_buf;
+	int ret = -1;
+	int num_pages;
+	int page_size = flash_page_size();
+	int block_size = flash_block_size();
+	int num_pages_per_blk = block_size/page_size;
+
+	tmp_buf = (unsigned char *)malloc(block_size - data_offset);
+	if (!tmp_buf)
+	{
+		dprintf(CRITICAL, "write_leb_data: Mem allocation failed\n");
+		return -1;
+	}
+
+	if (size < block_size - data_offset)
+		num_pages = size / page_size;
+	else
+		num_pages = calc_data_len(page_size, data,
+				block_size - data_offset);
+	memcpy(tmp_buf, data, num_pages * page_size);
+	ret = qpic_nand_write(peb * num_pages_per_blk + data_offset/page_size,
+			num_pages, tmp_buf, 0);
+	if (ret) {
+		dprintf(CRITICAL,
+			"write_vid_header: qpic_nand_write failed with %d\n", ret);
+		ret = -1;
+		goto out;
+	}
+
+	ret = 0;
+out:
+	free(tmp_buf);
+	return ret;
+}
+
+/**
  * scan_partition() - Collect the ec_headers info of a given partition
  * @ptn: partition to read the headers of
  *
@@ -257,7 +507,8 @@
 {
 	struct ubi_scan_info *si;
 	struct ubi_ec_hdr *ec_hdr;
-	unsigned i, curr_peb;
+	struct ubi_vid_hdr vid_hdr;
+	unsigned i;
 	unsigned long long sum = 0;
 	int page_size = flash_page_size();
 	int ret;
@@ -270,13 +521,13 @@
 	}
 
 	memset((void *)si, 0, sizeof(*si));
-	si->ec = malloc(ptn->length * sizeof(uint64_t));
-	if (!si->ec) {
+	si->pebs_data = malloc(ptn->length * sizeof(struct peb_info));
+	if (!si->pebs_data) {
 		dprintf(CRITICAL,"scan_partition: (%s) Memory allocation failed\n",
 				ptn->name);
-		goto out_failed_ec;
+		goto out_failed_pebs;
 	}
-	memset((void *)si->ec, 0, ptn->length * sizeof(uint64_t));
+	memset((void *)si->pebs_data, 0, ptn->length * sizeof(struct peb_info));
 
 	ec_hdr = malloc(UBI_EC_HDR_SIZE);
 	if (!ec_hdr) {
@@ -285,16 +536,18 @@
 		goto out_failed;
 	}
 
-	curr_peb = ptn->start;
 	si->vid_hdr_offs = 0;
 	si->image_seq = rand() & UBI_IMAGE_SEQ_BASE;
-
+	si->vtbl_peb1 = -1;
+	si->vtbl_peb2 = -1;
+	si->fastmap_sb = -1;
 	for (i = 0; i < ptn->length; i++){
-		ret = read_ec_hdr(curr_peb + i, ec_hdr);
+		ret = read_ec_hdr(ptn->start + i, ec_hdr);
 		switch (ret) {
 		case 1:
 			si->empty_cnt++;
-			si->ec[i] = UBI_MAX_ERASECOUNTER;
+			si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
+			si->pebs_data[i].status = UBI_EMPTY_PEB;
 			break;
 		case 0:
 			if (!si->vid_hdr_offs) {
@@ -304,44 +557,83 @@
 					si->vid_hdr_offs % page_size ||
 					si->data_offs % page_size) {
 					si->bad_cnt++;
-					si->ec[i] = UBI_MAX_ERASECOUNTER;
+					si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
 					si->vid_hdr_offs = 0;
 					continue;
 				}
 				if (BE32(ec_hdr->vid_hdr_offset) != si->vid_hdr_offs) {
 					si->bad_cnt++;
-					si->ec[i] = UBI_MAX_ERASECOUNTER;
+					si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
 					continue;
 				}
 				if (BE32(ec_hdr->data_offset) != si->data_offs) {
 					si->bad_cnt++;
-					si->ec[i] = UBI_MAX_ERASECOUNTER;
+					si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
 					continue;
 				}
 			}
-			si->good_cnt++;
-			si->ec[i] = BE64(ec_hdr->ec);
+			si->read_image_seq = BE32(ec_hdr->image_seq);
+			si->pebs_data[i].ec = BE64(ec_hdr->ec);
+			/* Now read the VID header to find if the peb is free */
+			ret = read_vid_hdr(ptn->start + i, &vid_hdr,
+					BE32(ec_hdr->vid_hdr_offset));
+			switch (ret) {
+			case 1:
+				si->pebs_data[i].status = UBI_FREE_PEB;
+				si->free_cnt++;
+				break;
+			case 0:
+				si->pebs_data[i].status = UBI_USED_PEB;
+				si->pebs_data[i].volume = BE32(vid_hdr.vol_id);
+				if (BE32(vid_hdr.vol_id) == UBI_LAYOUT_VOLUME_ID) {
+					if (si->vtbl_peb1 == -1)
+						si->vtbl_peb1 = i;
+					else if (si->vtbl_peb2 == -1)
+						si->vtbl_peb2 = i;
+					else
+						dprintf(CRITICAL,
+							"scan_partition: Found > 2 copies of vtbl");
+				}
+				if (BE32(vid_hdr.vol_id) == UBI_FM_SB_VOLUME_ID)
+					si->fastmap_sb = i;
+				si->used_cnt++;
+				break;
+			case -1:
+			default:
+				si->bad_cnt++;
+				si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
+				si->pebs_data[i].status = UBI_BAD_PEB;
+				break;
+			}
 			break;
 		case -1:
 		default:
 			si->bad_cnt++;
-			si->ec[i] = UBI_MAX_ERASECOUNTER;
+			si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
+			si->pebs_data[i].status = UBI_BAD_PEB;
 			break;
 		}
 	}
 
+	/* Sanity check */
+	if (si->bad_cnt + si->empty_cnt + si->free_cnt + si->used_cnt != (int)ptn->length) {
+		dprintf(CRITICAL,"scan_partition: peb count doesn't sum up \n");
+		goto out_failed;
+	}
+
 	/*
 	 * If less then 95% of the PEBs were "bad" (didn't have valid
 	 * ec header), then set mean_ec = UBI_DEF_ERACE_COUNTER.
 	 */
 	sum = 0;
-	if (si->good_cnt && (double)(si->good_cnt / ptn->length) * 100 > 95) {
+	if ((si->free_cnt + si->used_cnt) &&
+		(double)((si->free_cnt + si->used_cnt) / ptn->length) * 100 > 95) {
 		for (i = 0; i < ptn->length; i++) {
-			if (si->ec[i] == UBI_MAX_ERASECOUNTER)
+			if (si->pebs_data[i].ec == UBI_MAX_ERASECOUNTER)
 				continue;
-			sum += si->ec[i];
+			sum += si->pebs_data[i].ec;
 		}
-		si->mean_ec = sum / si->good_cnt;
+		si->mean_ec = sum / (si->free_cnt + si->used_cnt);
 	} else {
 		si->mean_ec = UBI_DEF_ERACE_COUNTER;
 	}
@@ -349,8 +641,8 @@
 	return si;
 
 out_failed:
-	free(si->ec);
-out_failed_ec:
+	free(si->pebs_data);
+out_failed_pebs:
 	free(si);
 	return NULL;
 }
@@ -369,8 +661,8 @@
 {
 	uint32_t crc;
 
-	if (si->ec[index] < UBI_MAX_ERASECOUNTER)
-		old_ech->ec = BE64(si->ec[index] + 1);
+	if (si->pebs_data[index].ec < UBI_MAX_ERASECOUNTER)
+		old_ech->ec = BE64(si->pebs_data[index].ec + 1);
 	else
 		old_ech->ec = BE64(si->mean_ec);
 
@@ -386,28 +678,25 @@
 	old_ech->hdr_crc = BE32(crc);
 }
 
-/**
- * calc_data_len - calculate how much real data is stored in the buffer
- * @page_size: min I/O of the device
- * @buf: a buffer with the contents of the physical eraseblock
- * @len: the buffer length
- *
- * This function calculates how much "real data" is stored in @buf and
- * returns the length (in number of pages). Continuous 0xFF bytes at the end
- * of the buffer are not considered as "real data".
- */
-static int calc_data_len(int page_size, const void *buf, int len)
+
+static void update_vid_header(struct ubi_vid_hdr *vid_hdr,
+		const struct ubi_scan_info *si, uint32_t vol_id,
+		uint32_t lnum, uint32_t data_pad)
 {
-	int i;
+	uint32_t crc;
 
-	for (i = len - 1; i >= 0; i--)
-		if (((const uint8_t *)buf)[i] != 0xFF)
-			break;
+	vid_hdr->vol_type = UBI_VID_DYNAMIC;
+	vid_hdr->sqnum = BE64(si->image_seq);
+	vid_hdr->vol_id = BE32(vol_id);
+	vid_hdr->lnum = BE32(lnum);
+	vid_hdr->compat = 0;
+	vid_hdr->data_pad = BE32(data_pad);
 
-	/* The resulting length must be aligned to the minimum flash I/O size */
-	len = i + 1;
-	len = (len + page_size - 1) / page_size;
-	return len;
+	vid_hdr->magic = BE32(UBI_VID_HDR_MAGIC);
+	vid_hdr->version = UBI_VERSION;
+	crc = mtd_crc32(UBI_CRC32_INIT,
+			(const void *)vid_hdr, UBI_VID_HDR_SIZE_CRC);
+	vid_hdr->hdr_crc = BE32(crc);
 }
 
 /**
@@ -450,7 +739,7 @@
 	int ret;
 
 	if (need_erase && qpic_nand_blk_erase(peb_num * num_pages_per_blk)) {
-		dprintf(INFO, "flash_ubi_img: erase of %d failed\n", peb_num);
+		dprintf(INFO, "ubi_erase_peb: erase of %d failed\n", peb_num);
 		return -1;
 	}
 	memset(&new_ech, 0xff, sizeof(new_ech));
@@ -459,10 +748,11 @@
 	/* Write new ec_header */
 	ret = write_ec_header(peb_num, &new_ech);
 	if (ret) {
-		dprintf(CRITICAL, "flash_ubi_img: write ec_header to %d failed\n",
+		dprintf(CRITICAL, "ubi_erase_peb: write ec_header to %d failed\n",
 				peb_num);
 		return -1;
 	}
+	si->pebs_data[peb_num - ptn_start].status = UBI_FREE_PEB;
 	return 0;
 }
 
@@ -609,7 +899,224 @@
 	}
 
 out:
-	free(si->ec);
+	free(si->pebs_data);
 	free(si);
 	return ret;
 }
+
+/**
+ * find_volume() - Find given volume in a partition by it's name
+ * @si: pointer to struct ubi_scan_info
+ * @ptn_start: PEB number the partition begins at
+ * @vol_name: name of the volume to search for
+ * @vol_info: info obout the found volume
+ *
+ * This functions reads the volume table, then iterates over all its records
+ * and searches for a volume with a given name. If found, the volume table
+ * record describing this volume is returned at @vol_info. The volume
+ * id returned as a return code of the function.
+ *
+ * Returns:
+ * -1 - if the volume was not found
+ * volume in dex when found
+ */
+static int find_volume(struct ubi_scan_info *si, int ptn_start,
+		const char *vol_name, struct ubi_vtbl_record *vol_info)
+{
+	int i, vtbl_records, vtbl_peb, ret = -1;
+	int block_size = flash_block_size();
+	void *leb_data;
+	struct ubi_vtbl_record *curr_vol;
+
+	if (si->vtbl_peb1 < 0) {
+		dprintf(CRITICAL,"find_volume: vtbl not found \n");
+		return -1;
+	}
+	vtbl_peb = si->vtbl_peb1;
+
+	vtbl_records = (block_size - si->data_offs) / UBI_VTBL_RECORD_SIZE;
+	if (vtbl_records > UBI_MAX_VOLUMES)
+		vtbl_records = UBI_MAX_VOLUMES;
+
+	leb_data = malloc(block_size - si->data_offs);
+	if (!leb_data) {
+		dprintf(CRITICAL,"find_volume: Memory allocation failed\n");
+		goto out_free_leb;
+	}
+retry:
+	/* First read the volume table */
+	if (read_leb_data(vtbl_peb + ptn_start, leb_data,
+			block_size - si->data_offs, si->data_offs)) {
+		dprintf(CRITICAL,"find_volume: read_leb_data failed\n");
+		if (vtbl_peb == si->vtbl_peb1 && si->vtbl_peb2 != -1) {
+			vtbl_peb = si->vtbl_peb2;
+			goto retry;
+		}
+		goto out_free_leb;
+	}
+
+	/* Now search for the required volume ID */
+	for (i = 0; i < vtbl_records; i++) {
+		curr_vol = (struct ubi_vtbl_record *)
+				(leb_data + UBI_VTBL_RECORD_SIZE*i);
+		if (!curr_vol->vol_type)
+			break;
+		if (!strcmp((char *)curr_vol->name, vol_name)) {
+			ret = i;
+			memcpy((void*)vol_info, curr_vol, sizeof(struct ubi_vtbl_record));
+			break;
+		}
+	}
+
+out_free_leb:
+	free(leb_data);
+	return ret;
+}
+
+/**
+ * write_one_peb() - writes data to a PEB, including VID header
+ * @curr_peb - PEB to write to
+ * @ptn_start: number of first PEB of the partition
+ * @si: pointer to struct ubi_scan_info
+ * @idx: index of required PEB in si->pebs_data array
+ * @lnum: lun number this LEB belongs to
+ * @vol_id: volume ID this PEB belongs to
+ * @data: data to write
+ * @size: size of the data
+ *
+ * Assumption: EC header correctly written and PEB erased
+ *
+ * Return codes:
+ * -1 - in case of error
+ *  0 - on success
+ */
+static int write_one_peb(int curr_peb, int ptn_start,
+		struct ubi_scan_info *si,
+		int lnum, int vol_id, void* data, int size)
+{
+	int ret;
+	struct ubi_vid_hdr vidh;
+
+	memset((void *)&vidh, 0, UBI_VID_HDR_SIZE);
+	update_vid_header(&vidh, si, vol_id, lnum, 0);
+	if (write_vid_header(curr_peb + ptn_start, &vidh, si->vid_hdr_offs)) {
+		dprintf(CRITICAL,
+				"update_ubi_vol: write_vid_header for peb %d failed \n",
+				curr_peb);
+		ret = -1;
+		goto out;
+	}
+
+	/* now write the data */
+	ret = write_leb_data(curr_peb + ptn_start, data, size, si->data_offs);
+	if (ret)
+		dprintf(CRITICAL, "update_ubi_vol: writing data to peb-%d failed\n",
+				curr_peb);
+	else
+		si->pebs_data[curr_peb].status = UBI_USED_PEB;
+out:
+	return ret;
+}
+
+/**
+ * update_ubi_vol() - Write the provided (UBI) image to given volume
+ * @ptn: partition holding the required volume
+ * @data: the image to write
+ * @size: size of the image to write
+ *
+ *  Return codes:
+ * -1 - in case of error
+ *  0 - on success
+ */
+int update_ubi_vol(struct ptentry *ptn, const char* vol_name,
+				void *data, unsigned size)
+{
+	struct ubi_scan_info *si;
+	int vol_id, vol_pebs, curr_peb = 0, ret = -1;
+	unsigned block_size = flash_block_size();
+	void *img_peb;
+	struct ubi_vtbl_record curr_vol;
+	int img_pebs, lnum = 0;
+
+	si = scan_partition(ptn);
+	if (!si) {
+		dprintf(CRITICAL, "update_ubi_vol: scan_partition failed\n");
+		return -1;
+	}
+	if (si->read_image_seq)
+		si->image_seq = si->read_image_seq;
+
+	vol_id = find_volume(si, ptn->start, vol_name, &curr_vol);
+	if (vol_id == -1) {
+		dprintf(CRITICAL, "update_ubi_vol: dint find volume\n");
+		goto out;
+	}
+	if (si->fastmap_sb > -1 &&
+			ubi_erase_peb(ptn->start + si->fastmap_sb, 1, si, ptn->start)) {
+		dprintf(CRITICAL, "update_ubi_vol: fastmap invalidation failed\n");
+		goto out;
+	}
+
+	img_pebs = size / (block_size - si->data_offs);
+	if (size % (block_size - si->data_offs))
+		img_pebs++;
+
+	vol_pebs = BE32(curr_vol.reserved_pebs);
+	if (img_pebs > vol_pebs) {
+		dprintf(CRITICAL,
+			"update_ubi_vol: Provided image is too big. Requires %d PEBs, avail. only %d\n",
+				img_pebs, vol_pebs);
+		goto out;
+	}
+
+	/* First erase all volume used PEBs */
+	curr_peb = 0;
+	while (curr_peb < (int)ptn->length) {
+		if (si->pebs_data[curr_peb].status != UBI_USED_PEB ||
+				si->pebs_data[curr_peb].volume != vol_id) {
+			curr_peb++;
+			continue;
+		}
+		if (ubi_erase_peb(ptn->start + curr_peb, 1, si, ptn->start))
+			goto out;
+		curr_peb++;
+	}
+
+	/* Flash the image */
+	img_peb = data;
+	lnum = 0;
+	for (curr_peb = 0;
+			curr_peb < (int)ptn->length && size && vol_pebs;
+			curr_peb++) {
+		if (si->pebs_data[curr_peb].status != UBI_FREE_PEB &&
+			si->pebs_data[curr_peb].status != UBI_EMPTY_PEB)
+			continue;
+
+		if (write_one_peb(curr_peb, ptn->start, si,
+				lnum++, vol_id, img_peb,
+				(size < block_size - si->data_offs ? size :
+						block_size - si->data_offs))) {
+			dprintf(CRITICAL, "update_ubi_vol: write_one_peb failed\n");
+			goto out;
+		}
+		if (size < block_size - si->data_offs)
+			size = 0;
+		else
+			size -= (block_size - si->data_offs);
+		vol_pebs--;
+		img_peb += block_size - si->data_offs;
+	}
+
+	if (size) {
+		dprintf(CRITICAL,
+			"update_ubi_vol: Not enough available PEBs for writing the volume\n");
+		goto out;
+	}
+	ret = 0;
+out:
+	free(si->pebs_data);
+	free(si);
+	return ret;
+}
+
+
diff --git a/platform/msm_shared/include/spmi.h b/platform/msm_shared/include/spmi.h
index 5e6deb4..85cd66a 100644
--- a/platform/msm_shared/include/spmi.h
+++ b/platform/msm_shared/include/spmi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012,2014 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012,2014-2015 The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -101,8 +101,6 @@
 #define SPMI_CMD_DEV_DESC_BLK_MASTER_READ    0x10
 #define SPMI_CMD_DEV_DESC_BLK_SLAVE_READ     0x11
 
-/* Max number of Peripherals supported by SPMI */
-#define MAX_PERIPH                           128
 #define PMIC_ARB_SPMI_HW_VERSION             (SPMI_BASE + 0xF000)
 
 enum spmi_geni_cmd_return_value{
diff --git a/platform/msm_shared/reboot.c b/platform/msm_shared/reboot.c
index abe2ce9..fb29ab5 100644
--- a/platform/msm_shared/reboot.c
+++ b/platform/msm_shared/reboot.c
@@ -122,7 +122,7 @@
 	/* For Reboot-bootloader and Dload cases do a warm reset
 	 * For Reboot cases do a hard reset
 	 */
-	if((reboot_reason == FASTBOOT_MODE) || (reboot_reason == DLOAD))
+	if((reboot_reason == FASTBOOT_MODE) || (reboot_reason == DLOAD) || (reboot_reason == RECOVERY_MODE))
 		reset_type = PON_PSHOLD_WARM_RESET;
 	else
 		reset_type = PON_PSHOLD_HARD_RESET;
diff --git a/platform/msm_shared/reboot.h b/platform/msm_shared/reboot.h
index cf03b27..7156c01 100644
--- a/platform/msm_shared/reboot.h
+++ b/platform/msm_shared/reboot.h
@@ -27,6 +27,7 @@
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #define FASTBOOT_MODE     0x77665500
+#define RECOVERY_MODE     0x77665502
 #define ALARM_BOOT        0x77665503
 #define RTC_TRG           4
 #define PON_SOFT_RB_SPARE 0x88F
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index 7e2cb3a..fe90e5d 100644
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -549,7 +549,14 @@
 			$(LOCAL_DIR)/qpic_nand.o \
 			$(LOCAL_DIR)/scm.o \
 			$(LOCAL_DIR)/dev_tree.o \
-			$(LOCAL_DIR)/gpio.o
+			$(LOCAL_DIR)/gpio.o \
+			$(LOCAL_DIR)/dload_util.o \
+			$(LOCAL_DIR)/shutdown_detect.o \
+			$(LOCAL_DIR)/certificate.o \
+			$(LOCAL_DIR)/image_verify.o \
+			$(LOCAL_DIR)/crypto_hash.o \
+			$(LOCAL_DIR)/crypto5_eng.o \
+			$(LOCAL_DIR)/crypto5_wrapper.o
 endif
 
 ifeq ($(ENABLE_BOOT_CONFIG_SUPPORT), 1)
diff --git a/platform/msm_shared/spmi.c b/platform/msm_shared/spmi.c
index d82fbb9..7408a9d 100644
--- a/platform/msm_shared/spmi.c
+++ b/platform/msm_shared/spmi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2014-2015, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -34,6 +34,7 @@
 #include <platform/irqs.h>
 #include <platform/interrupts.h>
 #include <malloc.h>
+#include <platform.h>
 
 #define PMIC_ARB_V2 0x20010000
 #define CHNL_IDX(sid, pid) ((sid << 8) | pid)
@@ -44,10 +45,11 @@
 static spmi_callback callback;
 static uint32_t pmic_arb_ver;
 static uint8_t *chnl_tbl;
+static uint32_t max_peripherals;
 
 static void spmi_lookup_chnl_number()
 {
-	int i;
+	uint32_t i;
 	uint8_t slave_id = 0;
 	uint8_t ppid_address = 0;
 	/* We need a max of sid (4 bits) + pid (8bits) of uint8_t's */
@@ -57,7 +59,7 @@
 	chnl_tbl = (uint8_t *) malloc(chnl_tbl_sz);
 	ASSERT(chnl_tbl);
 
-	for(i = 0; i < MAX_PERIPH ; i++)
+	for(i = 0; i < max_peripherals; i++)
 	{
 #if SPMI_CORE_V2
 		slave_id = (readl(PMIC_ARB_REG_CHLN(i)) & 0xf0000) >> 16;
@@ -74,6 +76,7 @@
 {
 	/* Read the version numver */
 	pmic_arb_ver = readl(PMIC_ARB_SPMI_HW_VERSION);
+	max_peripherals = platform_get_max_periph();
 
 	if (pmic_arb_ver < PMIC_ARB_V2)
 	{
diff --git a/platform/msm_shared/usb30_dwc.c b/platform/msm_shared/usb30_dwc.c
index 6f419cd..5ae8801 100644
--- a/platform/msm_shared/usb30_dwc.c
+++ b/platform/msm_shared/usb30_dwc.c
@@ -1730,7 +1730,7 @@
 
 	ep->bytes_queued = 0;
 
-	if (ep->type == EP_TYPE_CONTROL)
+	if (ep->type == EP_TYPE_CONTROL || ep->type == EP_TYPE_INTERRUPT)
 	{
 		memset(trb, 0, sizeof(dwc_trb_t));
 
diff --git a/platform/msm_shared/usb30_dwc.h b/platform/msm_shared/usb30_dwc.h
index 1a69a61..14402e7 100644
--- a/platform/msm_shared/usb30_dwc.h
+++ b/platform/msm_shared/usb30_dwc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -379,7 +379,7 @@
 } dwc_notify_event_t;
 
 /* maximum number of endpoints supported. */
-#define DWC_MAX_NUM_OF_EP     4
+#define DWC_MAX_NUM_OF_EP     8
 
 /* length of setup packet */
 #define DWC_SETUP_PKT_LEN    8
diff --git a/platform/msm_shared/usb30_udc.c b/platform/msm_shared/usb30_udc.c
index 0e5e1b0..d9d18a2 100644
--- a/platform/msm_shared/usb30_udc.c
+++ b/platform/msm_shared/usb30_udc.c
@@ -559,7 +559,7 @@
 
 						ep->number        = ept->num;
 						ep->dir           = ept->in;
-						ep->type          = EP_TYPE_BULK; /* the only one supported */
+						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 */
@@ -848,6 +848,7 @@
 
 static struct udc_endpoint *_udc_endpoint_alloc(uint8_t num,
 												uint8_t in,
+												uint8_t type,
 												uint16_t max_pkt)
 {
 	struct udc_endpoint *ept;
@@ -858,6 +859,7 @@
 
 	ept->maxpkt     = max_pkt;
 	ept->num        = num;
+	ept->type       = type;
 	ept->in         = !!in;
 	ept->maxburst   = 4;      /* no performance improvement is seen beyond burst size of 4 */
 	ept->trb_count  = 66;     /* each trb can transfer (16MB - 1). 65 for 1GB transfer + 1 for roundup/zero length pkt. */
@@ -881,8 +883,16 @@
 
 	if (type == UDC_TYPE_BULK_IN) {
 		in = 1;
+		type = EP_TYPE_BULK;
 	} else if (type == UDC_TYPE_BULK_OUT) {
 		in = 0;
+		type = EP_TYPE_BULK;
+	} else if (type == UDC_TYPE_INTR_IN) {
+		in = 1;
+		type = EP_TYPE_INTERRUPT;
+	} else if (type == UDC_TYPE_INTR_OUT){
+		in = 0;
+		type = EP_TYPE_INTERRUPT;
 	} else {
 		return 0;
 	}
@@ -891,7 +901,7 @@
 		uint32_t bit = in ? EPT_TX(n) : EPT_RX(n);
 		if (udc->ept_alloc_table & bit)
 			continue;
-		ept = _udc_endpoint_alloc(n, in, maxpkt);
+		ept = _udc_endpoint_alloc(n, in, type, maxpkt);
 		if (ept)
 			udc->ept_alloc_table |= bit;
 		return ept;
diff --git a/platform/msm_shared/usb30_udc.h b/platform/msm_shared/usb30_udc.h
index 02e86fa..97ef7e8 100644
--- a/platform/msm_shared/usb30_udc.h
+++ b/platform/msm_shared/usb30_udc.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
@@ -84,6 +84,7 @@
 struct udc_endpoint {
 	struct udc_endpoint *next;
 	uint8_t              num;
+	uint8_t              type;
 	uint8_t              in;
 	uint16_t             maxpkt;
 	uint32_t             maxburst;  /* max pkts that this ep can transfer before waiting for ack. */
diff --git a/project/msm8952.mk b/project/msm8952.mk
index 926697c..1a27c22 100644
--- a/project/msm8952.mk
+++ b/project/msm8952.mk
@@ -23,11 +23,11 @@
 #DEFINES += WITH_DEBUG_FBCON=1
 DEFINES += DEVICE_TREE=1
 #DEFINES += MMC_BOOT_BAM=1
-#DEFINES += CRYPTO_BAM=1
+DEFINES += CRYPTO_BAM=1
 DEFINES += SPMI_CORE_V2=1
 DEFINES += ABOOT_IGNORE_BOOT_HEADER_ADDRS=1
 
-#DEFINES += BAM_V170=1
+DEFINES += BAM_V170=1
 
 #Enable the feature of long press power on
 #DEFINES += LONG_PRESS_POWER_ON=1
@@ -35,7 +35,7 @@
 #Disable thumb mode
 ENABLE_THUMB := false
 
-#ENABLE_SDHCI_SUPPORT := 1
+ENABLE_SDHCI_SUPPORT := 1
 
 ifeq ($(ENABLE_SDHCI_SUPPORT),1)
 DEFINES += MMC_SDHCI_SUPPORT=1
diff --git a/target/init.c b/target/init.c
index 97809cc..9191572 100644
--- a/target/init.c
+++ b/target/init.c
@@ -59,6 +59,11 @@
     return 0;
 }
 
+__WEAK int update_ubi_vol(void)
+{
+    return 0;
+}
+
 __WEAK int target_is_emmc_boot(void)
 {
 #if _EMMC_BOOT
diff --git a/target/msm8952/init.c b/target/msm8952/init.c
index c61c631..445e132 100644
--- a/target/msm8952/init.c
+++ b/target/msm8952/init.c
@@ -60,23 +60,91 @@
 #define FASTBOOT_MODE           0x77665500
 #define PON_SOFT_RB_SPARE       0x88F
 
-static uint32_t mmc_sdc_base[] =
+#define CE1_INSTANCE            1
+#define CE_EE                   1
+#define CE_FIFO_SIZE            64
+#define CE_READ_PIPE            3
+#define CE_WRITE_PIPE           2
+#define CE_READ_PIPE_LOCK_GRP   0
+#define CE_WRITE_PIPE_LOCK_GRP  0
+#define CE_ARRAY_SIZE           20
+
+struct mmc_device *dev;
+
+static uint32_t mmc_pwrctl_base[] =
 	{ MSM_SDC1_BASE, MSM_SDC2_BASE };
 
+static uint32_t mmc_sdhci_base[] =
+	{ MSM_SDC1_SDHCI_BASE, MSM_SDC2_SDHCI_BASE };
+
+static uint32_t  mmc_sdc_pwrctl_irq[] =
+	{ SDCC1_PWRCTL_IRQ, SDCC2_PWRCTL_IRQ };
 
 void target_early_init(void)
 {
 #if WITH_DEBUG_UART
-	uart_dm_init(1, 0, BLSP1_UART1_BASE);
+	uart_dm_init(2, 0, BLSP1_UART1_BASE);
 #endif
 }
 
-void target_mmc_caps(struct mmc_host *host)
+static void set_sdc_power_ctrl()
 {
-	host->caps.ddr_mode = 0;
-	host->caps.hs200_mode = 0;
-	host->caps.bus_width = MMC_BOOT_BUS_WIDTH_8_BIT;
-	host->caps.hs_clk_rate = MMC_CLK_50MHZ;
+	/* Drive strength configs for sdc pins */
+	struct tlmm_cfgs sdc1_hdrv_cfg[] =
+	{
+		{ SDC1_CLK_HDRV_CTL_OFF,  TLMM_CUR_VAL_16MA, TLMM_HDRV_MASK, 0},
+		{ SDC1_CMD_HDRV_CTL_OFF,  TLMM_CUR_VAL_10MA, TLMM_HDRV_MASK, 0},
+		{ SDC1_DATA_HDRV_CTL_OFF, TLMM_CUR_VAL_10MA, TLMM_HDRV_MASK , 0},
+	};
+
+	/* Pull configs for sdc pins */
+	struct tlmm_cfgs sdc1_pull_cfg[] =
+	{
+		{ SDC1_CLK_PULL_CTL_OFF,  TLMM_NO_PULL, TLMM_PULL_MASK, 0},
+		{ SDC1_CMD_PULL_CTL_OFF,  TLMM_PULL_UP, TLMM_PULL_MASK, 0},
+		{ SDC1_DATA_PULL_CTL_OFF, TLMM_PULL_UP, TLMM_PULL_MASK, 0},
+	};
+
+	/* Set the drive strength & pull control values */
+	tlmm_set_hdrive_ctrl(sdc1_hdrv_cfg, ARRAY_SIZE(sdc1_hdrv_cfg));
+	tlmm_set_pull_ctrl(sdc1_pull_cfg, ARRAY_SIZE(sdc1_pull_cfg));
+}
+
+void target_sdc_init()
+{
+	struct mmc_config_data config;
+
+	/* Set drive strength & pull ctrl values */
+	set_sdc_power_ctrl();
+
+	/* Try slot 1*/
+	config.slot          = 1;
+	config.bus_width     = DATA_BUS_WIDTH_8BIT;
+	config.max_clk_rate  = MMC_CLK_177MHZ;
+	config.sdhc_base     = mmc_sdhci_base[config.slot - 1];
+	config.pwrctl_base   = mmc_pwrctl_base[config.slot - 1];
+	config.pwr_irq       = mmc_sdc_pwrctl_irq[config.slot - 1];
+	config.hs400_support = 1;
+
+	if (!(dev = mmc_init(&config))) {
+	/* Try slot 2 */
+		config.slot          = 2;
+		config.max_clk_rate  = MMC_CLK_200MHZ;
+		config.sdhc_base     = mmc_sdhci_base[config.slot - 1];
+		config.pwrctl_base   = mmc_pwrctl_base[config.slot - 1];
+		config.pwr_irq       = mmc_sdc_pwrctl_irq[config.slot - 1];
+		config.hs400_support = 0;
+
+		if (!(dev = mmc_init(&config))) {
+			dprintf(CRITICAL, "mmc init failed!");
+			ASSERT(0);
+		}
+	}
+}
+
+void *target_mmc_device()
+{
+	return (void *) dev;
 }
 
 /* Return 1 if vol_up pressed */
@@ -144,23 +212,18 @@
 
 	target_keystatus();
 
-	/* Trying Slot 1*/
-	slot = 1;
-	base_addr = mmc_sdc_base[slot - 1];
-	if (mmc_boot_main(slot, base_addr))
+	target_sdc_init();
+	if (partition_read_table())
 	{
-
-	/* Trying Slot 2 next */
-	slot = 2;
-	base_addr = mmc_sdc_base[slot - 1];
-	if (mmc_boot_main(slot, base_addr)) {
-		dprintf(CRITICAL, "mmc init failed!");
+		dprintf(CRITICAL, "Error reading the partition table info\n");
 		ASSERT(0);
-		}
 	}
+
 #if LONG_PRESS_POWER_ON
 	shutdown_detect();
 #endif
+	if (target_use_signed_kernel())
+		target_crypto_init_params();
 }
 
 void target_serialno(unsigned char *buf)
@@ -314,8 +377,129 @@
 	if (is_cold_boot &&
 			(!(pon_reason & HARD_RST)) &&
 			(!(pon_reason & KPDPWR_N)) &&
-			((pon_reason & USB_CHG) || (pon_reason & DC_CHG) || (pon_reason & CBLPWR_N)))
+			((pon_reason & USB_CHG)))
 		return 1;
 	else
 		return 0;
 }
+
+void target_uninit(void)
+{
+	mmc_put_card_to_sleep(dev);
+	sdhci_mode_disable(&dev->host);
+	if (crypto_initialized())
+		crypto_eng_cleanup();
+
+	if (target_is_ssd_enabled())
+		clock_ce_disable(CE1_INSTANCE);
+}
+
+void target_usb_init(void)
+{
+	uint32_t val;
+
+	/* Select and enable external configuration with USB PHY */
+	ulpi_write(ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT, ULPI_MISC_A_SET);
+
+	/* Enable sess_vld */
+	val = readl(USB_GENCONFIG_2) | GEN2_SESS_VLD_CTRL_EN;
+	writel(val, USB_GENCONFIG_2);
+
+	/* Enable external vbus configuration in the LINK */
+	val = readl(USB_USBCMD);
+	val |= SESS_VLD_CTRL;
+	writel(val, USB_USBCMD);
+}
+
+void target_usb_stop(void)
+{
+	/* Disable VBUS mimicing in the controller. */
+	ulpi_write(ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT, ULPI_MISC_A_CLEAR);
+}
+
+/* Do any target specific intialization needed before entering fastboot mode */
+void target_fastboot_init(void)
+{
+	if (target_is_ssd_enabled()) {
+		clock_ce_enable(CE1_INSTANCE);
+		target_load_ssd_keystore();
+	}
+}
+
+void target_load_ssd_keystore(void)
+{
+	uint64_t ptn;
+	int      index;
+	uint64_t size;
+	uint32_t *buffer = NULL;
+
+	if (!target_is_ssd_enabled())
+		return;
+
+	index = partition_get_index("ssd");
+
+	ptn = partition_get_offset(index);
+	if (ptn == 0){
+		dprintf(CRITICAL, "Error: ssd partition not found\n");
+		return;
+	}
+
+	size = partition_get_size(index);
+	if (size == 0) {
+		dprintf(CRITICAL, "Error: invalid ssd partition size\n");
+		return;
+	}
+
+	buffer = memalign(CACHE_LINE, ROUNDUP(size, CACHE_LINE));
+	if (!buffer) {
+		dprintf(CRITICAL, "Error: allocating memory for ssd buffer\n");
+		return;
+	}
+
+	if (mmc_read(ptn, buffer, size)) {
+		dprintf(CRITICAL, "Error: cannot read data\n");
+		free(buffer);
+		return;
+	}
+
+	clock_ce_enable(CE1_INSTANCE);
+	scm_protect_keystore(buffer, size);
+	clock_ce_disable(CE1_INSTANCE);
+	free(buffer);
+}
+
+crypto_engine_type board_ce_type(void)
+{
+	return CRYPTO_ENGINE_TYPE_HW;
+}
+
+/* Set up params for h/w CE. */
+void target_crypto_init_params()
+{
+	struct crypto_init_params ce_params;
+
+	/* Set up base addresses and instance. */
+	ce_params.crypto_instance  = CE1_INSTANCE;
+	ce_params.crypto_base      = MSM_CE1_BASE;
+	ce_params.bam_base         = MSM_CE1_BAM_BASE;
+
+	/* Set up BAM config. */
+	ce_params.bam_ee               = CE_EE;
+	ce_params.pipes.read_pipe      = CE_READ_PIPE;
+	ce_params.pipes.write_pipe     = CE_WRITE_PIPE;
+	ce_params.pipes.read_pipe_grp  = CE_READ_PIPE_LOCK_GRP;
+	ce_params.pipes.write_pipe_grp = CE_WRITE_PIPE_LOCK_GRP;
+
+	/* Assign buffer sizes. */
+	ce_params.num_ce           = CE_ARRAY_SIZE;
+	ce_params.read_fifo_size   = CE_FIFO_SIZE;
+	ce_params.write_fifo_size  = CE_FIFO_SIZE;
+
+	/* BAM is initialized by TZ for this platform.
+	 * Do not do it again as the initialization address space
+	 * is locked.
+	 */
+	ce_params.do_bam_init      = 0;
+
+	crypto_init_params(&ce_params);
+}