Merge "dev: pm8x41: Re-write the enable mpp as ADC api"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 42b2179..0b9fd12 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -177,6 +177,8 @@
 static device_info device = {DEVICE_MAGIC, 0, 0, 0, 0, {0}, {0},{0}};
 static bool is_allow_unlock = 0;
 
+static char frp_ptns[2][8] = {"config","frp"};
+
 struct atag_ptbl_entry
 {
 	char name[16];
@@ -1586,7 +1588,6 @@
 
 static int read_allow_oem_unlock(device_info *dev)
 {
-	const char *ptn_name = "frp";
 	unsigned offset;
 	int index;
 	unsigned long long ptn;
@@ -1594,11 +1595,15 @@
 	unsigned blocksize = mmc_get_device_blocksize();
 	char buf[blocksize];
 
-	index = partition_get_index(ptn_name);
+	index = partition_get_index(frp_ptns[0]);
 	if (index == INVALID_PTN)
 	{
-		dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
-		return -1;
+		index = partition_get_index(frp_ptns[1]);
+		if (index == INVALID_PTN)
+		{
+			dprintf(CRITICAL, "Neither '%s' nor '%s' partition found\n", frp_ptns[0],frp_ptns[1]);
+			return -1;
+		}
 	}
 
 	ptn = partition_get_offset(index);
@@ -1618,20 +1623,22 @@
 
 static int write_allow_oem_unlock(bool allow_unlock)
 {
-	const char *ptn_name = "frp";
 	unsigned offset;
-
 	int index;
 	unsigned long long ptn;
 	unsigned long long ptn_size;
 	unsigned blocksize = mmc_get_device_blocksize();
 	char buf[blocksize];
 
-	index = partition_get_index(ptn_name);
+	index = partition_get_index(frp_ptns[0]);
 	if (index == INVALID_PTN)
 	{
-		dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
-		return -1;
+		index = partition_get_index(frp_ptns[1]);
+		if (index == INVALID_PTN)
+		{
+			dprintf(CRITICAL, "Neither '%s' nor '%s' partition found\n", frp_ptns[0],frp_ptns[1]);
+			return -1;
+		}
 	}
 
 	ptn = partition_get_offset(index);
@@ -1753,7 +1760,7 @@
 			if (is_secure_boot_enable())
 				info->is_unlocked = 0;
 			else
-				info->is_verified = 1;
+				info->is_unlocked = 1;
 			info->is_tampered = 0;
 			info->charger_screen_enabled = 0;
 			write_device_info(info);
diff --git a/arch/arm/include/arch/defines.h b/arch/arm/include/arch/defines.h
index 6f0985a..ffa766f 100644
--- a/arch/arm/include/arch/defines.h
+++ b/arch/arm/include/arch/defines.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2008 Travis Geiselbrecht
  *
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files
@@ -36,6 +36,8 @@
  #define CACHE_LINE 32
 #elif defined(ARM_CPU_CORE_KRAIT) || defined(ARM_CPU_CORE_A7)
  #define CACHE_LINE 64
+#elif defined(ARM_CPU_CORE_KRYO)
+ #define CACHE_LINE 128
 #else
  #error unknown cpu
 #endif
diff --git a/dev/gcdb/display/fastboot_oem_display.h b/dev/gcdb/display/fastboot_oem_display.h
index 7492d2f..9dd8b5c 100644
--- a/dev/gcdb/display/fastboot_oem_display.h
+++ b/dev/gcdb/display/fastboot_oem_display.h
@@ -30,9 +30,14 @@
 #ifndef _FASTBOOT_OEM_DISPLAY_H_
 #define _FASTBOOT_OEM_DISPLAY_H_
 
-/*---------------------------------------------------------------------------*/
-/* Lookup table for skip panels                                              */
-/*---------------------------------------------------------------------------*/
+#define SIM_OVERRIDE_LEN 10
+
+enum {
+    SIM_NONE,
+    SIM_MODE,
+    SIM_SWTE,
+    SIM_HWTE,
+};
 
 struct panel_lookup_list {
 	char name[MAX_PANEL_ID_LEN];
@@ -40,6 +45,15 @@
 	bool is_split_dsi;
 };
 
+struct sim_lookup_list {
+	uint32_t sim_mode;
+	char override_string[SIM_OVERRIDE_LEN];
+};
+
+/*---------------------------------------------------------------------------*/
+/* Lookup table for skip panels                                              */
+/*---------------------------------------------------------------------------*/
+
 struct panel_lookup_list lookup_skip_panels[] = {
 	{"adv7533_1080p_video", "qcom,mdss_dsi_adv7533_1080p60_video", false},
 	{"adv7533_720p_video", "qcom,mdss_dsi_adv7533_720p60_video", false},
@@ -89,4 +103,10 @@
 	{"truly_wvga_video", "qcom,mdss_dsi_truly_wvga_video", false},
 };
 
+struct sim_lookup_list lookup_sim[] = {
+	{SIM_MODE, "sim"},
+	{SIM_SWTE, "sim-swte"},
+	{SIM_HWTE, "sim-hwte"},
+};
+
 #endif /*_FASTBOOT_OEM_DISPLAY_H_ */
diff --git a/dev/gcdb/display/gcdb_display.c b/dev/gcdb/display/gcdb_display.c
index bfb1153..d4fe865 100644
--- a/dev/gcdb/display/gcdb_display.c
+++ b/dev/gcdb/display/gcdb_display.c
@@ -408,6 +408,45 @@
 	return panelstruct;
 }
 
+static void mdss_dsi_set_pll_src(void)
+{
+	struct oem_panel_data *oem_data = mdss_dsi_get_oem_data_ptr();
+
+	if (panelstruct.paneldata->panel_operating_mode & USE_DSI1_PLL_FLAG)
+		oem_data->dsi_pll_src = DSI_PLL1;
+
+	if (strcmp(oem_data->sec_panel, "")) {
+		if (oem_data->dsi_pll_src != DSI_PLL_DEFAULT) {
+			dprintf(CRITICAL, "Dual DSI config detected!"
+				"Use default PLL\n");
+			oem_data->dsi_pll_src = DSI_PLL_DEFAULT;
+		}
+	} else if (panelstruct.paneldata->slave_panel_node_id) {
+		if((dsi_video_mode_phy_db.pll_type != DSI_PLL_TYPE_THULIUM)
+			&& (oem_data->dsi_pll_src == DSI_PLL1)) {
+			dprintf(CRITICAL, "Split DSI on 28nm/20nm!"
+				"Use DSI PLL0\n");
+			oem_data->dsi_pll_src = DSI_PLL0;
+		}
+	} else {
+		if ((dsi_video_mode_phy_db.pll_type != DSI_PLL_TYPE_THULIUM)
+			&& !strcmp(panelstruct.paneldata->panel_destination,
+			"DISPLAY_1") && (oem_data->dsi_pll_src == DSI_PLL1)) {
+			dprintf(CRITICAL, "Single DSI with DSI-0 on 28nm/20nm!"
+				"Use DSI PLL0\n");
+			oem_data->dsi_pll_src = DSI_PLL0;
+		}
+	}
+
+	if (oem_data->dsi_pll_src == DSI_PLL1)
+		panelstruct.paneldata->panel_operating_mode |=
+			USE_DSI1_PLL_FLAG;
+	else
+		panelstruct.paneldata->panel_operating_mode &=
+			~USE_DSI1_PLL_FLAG;
+
+}
+
 int gcdb_display_init(const char *panel_name, uint32_t rev, void *base)
 {
 	int ret = NO_ERROR;
@@ -419,6 +458,7 @@
 
 	if (pan_type == PANEL_TYPE_DSI) {
 		target_dsi_phy_config(&dsi_video_mode_phy_db);
+		mdss_dsi_set_pll_src();
 		if (dsi_panel_init(&(panel.panel_info), &panelstruct)) {
 			dprintf(CRITICAL, "DSI panel init failed!\n");
 			ret = ERROR;
diff --git a/dev/gcdb/display/gcdb_display.h b/dev/gcdb/display/gcdb_display.h
index 1fbc2f7..088aa05 100755
--- a/dev/gcdb/display/gcdb_display.h
+++ b/dev/gcdb/display/gcdb_display.h
@@ -43,6 +43,8 @@
 #define BIST_SIZE 6
 #define LANE_SIZE 45
 
+#define DSI_CFG_SIZE 15
+
 /*---------------------------------------------------------------------------*/
 /* API                                                                       */
 /*---------------------------------------------------------------------------*/
@@ -62,12 +64,23 @@
 	struct msm_panel_info *pinfo, struct mdss_dsi_phy_ctrl *phy_db);
 void set_panel_cmd_string(const char *panel_name);
 struct oem_panel_data mdss_dsi_get_oem_data(void);
+struct oem_panel_data *mdss_dsi_get_oem_data_ptr(void);
 struct panel_struct mdss_dsi_get_panel_data(void);
 
 struct oem_panel_data  {
 	char panel[MAX_PANEL_ID_LEN];
+	char sec_panel[MAX_PANEL_ID_LEN];
 	bool cont_splash;
 	bool skip;
+	uint32_t sim_mode;
+	char dsi_config[DSI_CFG_SIZE];
+	uint32_t dsi_pll_src;
+};
+
+enum {
+    DSI_PLL_DEFAULT,
+    DSI_PLL0,
+    DSI_PLL1,
 };
 
 #endif /*_GCDB_DISPLAY_H_ */
diff --git a/dev/gcdb/display/gcdb_display_param.c b/dev/gcdb/display/gcdb_display_param.c
index 027207c..ce98cf0 100644
--- a/dev/gcdb/display/gcdb_display_param.c
+++ b/dev/gcdb/display/gcdb_display_param.c
@@ -37,38 +37,47 @@
 #include "target/display.h"
 #include "fastboot_oem_display.h"
 
-struct oem_panel_data oem_data = {{'\0'}, false, false};
+struct oem_panel_data oem_data = {{'\0'}, {'\0'}, false, false, SIM_NONE, "single_dsi", DSI_PLL_DEFAULT};
 
-void panel_name_to_dt_string(struct panel_lookup_list supp_panels[],
+static int panel_name_to_dt_string(struct panel_lookup_list supp_panels[],
 			  uint32_t supp_panels_size,
-			  const char *panel_name, char **panel_node,
-			  char **slave_panel_node, int *panel_mode)
+			  const char *panel_name, char **panel_node)
 {
 	uint32_t i;
 
 	if (!panel_name) {
 		dprintf(CRITICAL, "Invalid panel name\n");
-		return;
+		return ERR_NOT_VALID;
 	}
 
 	for (i = 0; i < supp_panels_size; i++) {
 		if (!strncmp(panel_name, supp_panels[i].name,
 			MAX_PANEL_ID_LEN)) {
 			*panel_node = supp_panels[i].panel_dt_string;
-			if (supp_panels[i].is_split_dsi) {
-				*slave_panel_node =
-					supp_panels[i].panel_dt_string;
-				*panel_mode = DUAL_DSI_FLAG;
-			} else {
-				*panel_mode = 0;
-			}
+			return supp_panels[i].is_split_dsi;
+		}
+	}
+
+	dprintf(CRITICAL, "Panel_name:%s not found in lookup table\n",
+		panel_name);
+	return ERR_NOT_FOUND;
+}
+
+void sim_override_to_cmdline(struct sim_lookup_list sim[],
+			  uint32_t sim_size, uint32_t sim_mode,
+			  char **sim_string)
+{
+	uint32_t i;
+
+	for (i = 0; i < sim_size; i++) {
+		if (sim_mode == sim[i].sim_mode) {
+			*sim_string = sim[i].override_string;
 			break;
 		}
 	}
 
-	if (i == supp_panels_size)
-		dprintf(CRITICAL, "Panel_name:%s not found in lookup table\n",
-			panel_name);
+	if (i == sim_size)
+		dprintf(CRITICAL, "Sim_mode not found in lookup table\n");
 }
 
 struct oem_panel_data mdss_dsi_get_oem_data(void)
@@ -76,21 +85,106 @@
 	return oem_data;
 }
 
+struct oem_panel_data *mdss_dsi_get_oem_data_ptr(void)
+{
+	return &oem_data;
+}
+
+static char *get_panel_token_end(const char *string)
+{
+	char *ch_hash = NULL, *ch_col = NULL;
+
+	/* ':' and '#' are delimiters in the string */
+	ch_col = strchr((char *) string, ':');
+	ch_hash = strchr((char *) string, '#');
+
+	if (ch_col && ch_hash)
+		return ((ch_col < ch_hash) ? ch_col : ch_hash);
+	else if (ch_col)
+		return ch_col;
+	else if (ch_hash)
+		return ch_hash;
+	return NULL;
+}
+
 void set_panel_cmd_string(const char *panel_name)
 {
-	char *ch = NULL;
+	char *ch = NULL, *ch_tmp = NULL;
 	int i;
 
 	panel_name += strspn(panel_name, " ");
 
-	/* Panel string */
-	ch = strchr((char *) panel_name, ':');
+	/* Primary panel string */
+	ch = strstr((char *) panel_name, "prim:");
 	if (ch) {
-		for (i = 0; (panel_name + i) < ch; i++)
-			oem_data.panel[i] = *(panel_name + i);
+		/*
+		 * Parse the primary panel for cases where 'prim' prefix
+		 * is present in the fastboot oem command before primary
+		 * panel string.
+		 * Examples:
+		 * 1.) fastboot oem select-display-panel prim:jdi_1080p_video:sec:sharp_1080p_cmd
+		 * 2.) fastboot oem select-display-panel prim:jdi_1080p_video:skip:sec:sharp_1080p_cmd
+		 * 3.) fastboot oem select-display-panel prim:jdi_1080p_video:disable:sec:sharp_1080p_cmd
+		 * 4.) fastboot oem select-display-panel prim:jdi_1080p_video:skip#sim:sec:sharp_1080p_cmd
+		 */
+		ch += 5;
+		ch_tmp = get_panel_token_end((const char*) ch);
+		if (!ch_tmp)
+			ch_tmp = ch + strlen(ch);
+		for (i = 0; (ch + i) < ch_tmp; i++)
+			oem_data.panel[i] = *(ch + i);
 		oem_data.panel[i] = '\0';
 	} else {
-		strlcpy(oem_data.panel, panel_name, MAX_PANEL_ID_LEN);
+		/*
+		 * Check if secondary panel string is present.
+		 * The 'prim' prefix definitely needs to be present
+		 * to specify primary panel for cases where secondary panel
+		 * is also specified in fastboot oem command. Otherwise, it
+		 * becomes tough to parse the fastboot oem command for primary
+		 * panel. If 'sec' prefix is used without 'prim' prefix, it
+		 * means the default panel needs to be picked as primary panel.
+		 * Example:
+		 * fastboot oem select-display-panel sec:sharp_1080p_cmd
+		 */
+		ch = strstr((char *) panel_name, "sec:");
+		if (!ch) {
+			/*
+			 * This code will be executed for cases where the
+			 * secondary panel is not specified i.e., single/split
+			 * DSI cases.
+			 * Examples:
+			 * 1.) fastboot oem select-display-panel jdi_1080p_video
+			 * 2.) fastboot oem select-display-panel sharp_1080p_cmd:skip
+			 * 3.) fastboot oem select-display-panel sharp_1080p_cmd:disable
+			 * 4.) fastboot oem select-display-panel sim_cmd_panel#sim-swte
+			 */
+			ch = get_panel_token_end(panel_name);
+			if (ch) {
+				for (i = 0; (panel_name + i) < ch; i++)
+					oem_data.panel[i] =
+						*(panel_name + i);
+				oem_data.panel[i] = '\0';
+			} else {
+				strlcpy(oem_data.panel, panel_name,
+					MAX_PANEL_ID_LEN);
+			}
+		}
+	}
+
+	/*
+	 * Secondary panel string.
+	 * This is relatively simple. The secondary panel string gets
+	 * parsed if the 'sec' prefix is present.
+	 */
+	ch = strstr((char *) panel_name, "sec:");
+	if (ch) {
+		ch += 4;
+		ch_tmp = get_panel_token_end((const char*) ch);
+		if (!ch_tmp)
+			ch_tmp = ch + strlen(ch);
+		for (i = 0; (ch + i) < ch_tmp; i++)
+			oem_data.sec_panel[i] = *(ch + i);
+		oem_data.sec_panel[i] = '\0';
 	}
 
 	/* Skip LK configuration */
@@ -100,11 +194,33 @@
 	/* Cont. splash status */
 	ch = strstr((char *) panel_name, ":disable");
 	oem_data.cont_splash = ch ? false : true;
+
+	/* DSI PLL source */
+	ch = strstr((char *) panel_name, ":pll0");
+	if (ch) {
+		oem_data.dsi_pll_src = DSI_PLL0;
+	} else {
+		ch = strstr((char *) panel_name, ":pll1");
+		if (ch)
+			oem_data.dsi_pll_src = DSI_PLL1;
+	}
+
+	/* Simulator status */
+	oem_data.sim_mode = SIM_NONE;
+	if (strstr((char *) panel_name, "#sim-hwte"))
+		oem_data.sim_mode = SIM_HWTE;
+	else if (strstr((char *) panel_name, "#sim-swte"))
+		oem_data.sim_mode = SIM_SWTE;
+	else if (strstr((char *) panel_name, "#sim"))
+		oem_data.sim_mode = SIM_MODE;
+
 }
 
 static bool mdss_dsi_set_panel_node(char *panel_name, char **dsi_id,
 		char **panel_node, char **slave_panel_node, int *panel_mode)
 {
+	int rc = 0;
+
 	if (!strcmp(panel_name, SIM_VIDEO_PANEL)) {
 		*dsi_id = SIM_DSI_ID;
 		*panel_node = SIM_VIDEO_PANEL_NODE;
@@ -126,12 +242,21 @@
 	} else if (oem_data.skip) {
 		/* For skip panel case, check the lookup table */
 		*dsi_id = SIM_DSI_ID;
-		panel_name_to_dt_string(lookup_skip_panels,
+		rc = panel_name_to_dt_string(lookup_skip_panels,
 			ARRAY_SIZE(lookup_skip_panels), panel_name,
-			panel_node, slave_panel_node, panel_mode);
+			panel_node);
+		if (rc < 0) {
+			return false;
+		} else if (rc == 1) {
+			*slave_panel_node = *panel_node;
+			*panel_mode = DUAL_DSI_FLAG;
+		} else {
+			*panel_mode = 0;
+		}
 	} else {
 		return false;
 	}
+
 	return true;
 }
 
@@ -140,15 +265,16 @@
 	char *dsi_id = NULL;
 	char *panel_node = NULL;
 	char *slave_panel_node = NULL;
+	char *sim_mode_string = NULL;
 	uint16_t dsi_id_len = 0, panel_node_len = 0, slave_panel_node_len = 0;
 	uint32_t arg_size = 0;
-	bool ret = true;
-	bool rc;
+	bool ret = true, rc;
+	int ret_val;
 	char *default_str;
 	struct panel_struct panelstruct;
 	int panel_mode = SPLIT_DISPLAY_FLAG | DUAL_PIPE_FLAG | DST_SPLIT_FLAG;
 	int prefix_string_len = strlen(DISPLAY_CMDLINE_PREFIX);
-	char *sctl_string;
+	char *sctl_string, *pll_src_string = NULL;
 
 	panelstruct = mdss_dsi_get_panel_data();
 
@@ -196,13 +322,44 @@
 		return false;
 	}
 
+	if (oem_data.sec_panel) {
+		if (panel_mode & (DUAL_DSI_FLAG | SPLIT_DISPLAY_FLAG |
+			DST_SPLIT_FLAG)) {
+			dprintf(CRITICAL, "Invalid config: Primary panel is"
+				"split DSI and still secondary panel passed\n");
+		} else {
+			ret_val = panel_name_to_dt_string(lookup_skip_panels,
+				ARRAY_SIZE(lookup_skip_panels), oem_data.sec_panel,
+				&slave_panel_node);
+			if (ret_val < 0) {
+				dprintf(CRITICAL, "Sec. panel not found."
+					" Continue with primary panel\n");
+			} else if (ret_val == 1) {
+				dprintf(CRITICAL, "Invalid config: Secondary panel cant"
+					"be split DSI. Continue with primary panel\n");
+				slave_panel_node = NULL;
+			}
+		}
+	}
+
+	/* Check for the DSI configuration */
+	if (slave_panel_node && (panel_mode & (DUAL_DSI_FLAG |
+		SPLIT_DISPLAY_FLAG | DST_SPLIT_FLAG)))
+		strcpy(oem_data.dsi_config, "split_dsi");
+	else if (slave_panel_node)
+		strcpy(oem_data.dsi_config, "dual_dsi");
+	else
+		strcpy(oem_data.dsi_config, "single_dsi");
+
+	arg_size = DSI_CFG_STRING_LEN + strlen(oem_data.dsi_config);
+
 	dsi_id_len = strlen(dsi_id);
 	panel_node_len = strlen(panel_node);
 	if (!slave_panel_node || !strcmp(slave_panel_node, ""))
 		slave_panel_node = NO_PANEL_CONFIG;
 	slave_panel_node_len = strlen(slave_panel_node);
 
-	arg_size = prefix_string_len + dsi_id_len + panel_node_len +
+	arg_size += prefix_string_len + dsi_id_len + panel_node_len +
 						LK_OVERRIDE_PANEL_LEN + 1;
 
 	if (panelstruct.paneldata &&
@@ -213,6 +370,35 @@
 
 	arg_size += strlen(sctl_string) + slave_panel_node_len;
 
+	if (oem_data.skip && !strcmp(oem_data.dsi_config, "dual_dsi") &&
+		(oem_data.dsi_pll_src != DSI_PLL_DEFAULT)) {
+		dprintf(CRITICAL, "Dual DSI config detected!"
+			" Use default PLL\n");
+		oem_data.dsi_pll_src = DSI_PLL_DEFAULT;
+	}
+
+	if (oem_data.dsi_pll_src != DSI_PLL_DEFAULT) {
+		if (oem_data.dsi_pll_src == DSI_PLL0)
+			pll_src_string = DSI_PLL0_STRING;
+		else
+			pll_src_string = DSI_PLL1_STRING;
+
+		arg_size += strlen(pll_src_string);
+	}
+
+	if (oem_data.sim_mode != SIM_NONE) {
+		sim_override_to_cmdline(lookup_sim,
+			ARRAY_SIZE(lookup_sim), oem_data.sim_mode,
+			&sim_mode_string);
+		if (sim_mode_string) {
+			arg_size += LK_SIM_OVERRIDE_LEN +
+				strlen(sim_mode_string);
+		} else {
+			dprintf(CRITICAL, "SIM string NULL but mode is not NONE\n");
+			return false;
+		}
+	}
+
 	if (buf_size < arg_size) {
 		dprintf(CRITICAL, "display command line buffer is small\n");
 		ret = false;
@@ -230,14 +416,40 @@
 		buf_size -= dsi_id_len;
 
 		strlcpy(pbuf, panel_node, buf_size);
-
 		pbuf += panel_node_len;
 		buf_size -= panel_node_len;
 
 		strlcpy(pbuf, sctl_string, buf_size);
 		pbuf += strlen(sctl_string);
 		buf_size -= strlen(sctl_string);
+
 		strlcpy(pbuf, slave_panel_node, buf_size);
+		pbuf += slave_panel_node_len;
+		buf_size -= slave_panel_node_len;
+
+		strlcpy(pbuf, DSI_CFG_STRING, buf_size);
+		pbuf += DSI_CFG_STRING_LEN;
+		buf_size -= DSI_CFG_STRING_LEN;
+
+		strlcpy(pbuf, oem_data.dsi_config, buf_size);
+		pbuf += strlen(oem_data.dsi_config);
+		buf_size -= strlen(oem_data.dsi_config);
+
+		if (pll_src_string) {
+			strlcpy(pbuf, pll_src_string, buf_size);
+			pbuf += strlen(pll_src_string);
+			buf_size -= strlen(pll_src_string);
+		}
+
+		if (sim_mode_string) {
+			strlcpy(pbuf, LK_SIM_OVERRIDE, buf_size);
+			pbuf += LK_SIM_OVERRIDE_LEN;
+			buf_size -= LK_SIM_OVERRIDE_LEN;
+
+			strlcpy(pbuf, sim_mode_string, buf_size);
+			pbuf += strlen(sim_mode_string);
+			buf_size -= strlen(sim_mode_string);
+		}
 	}
 	return ret;
 }
diff --git a/dev/gcdb/display/include/display_resource.h b/dev/gcdb/display/include/display_resource.h
index 6fc177a..12437aa 100755
--- a/dev/gcdb/display/include/display_resource.h
+++ b/dev/gcdb/display/include/display_resource.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
@@ -42,11 +42,20 @@
 #define LK_OVERRIDE_PANEL      "1:"
 #define LK_OVERRIDE_PANEL_LEN  2
 
+#define LK_SIM_OVERRIDE     "#override:"
+#define LK_SIM_OVERRIDE_LEN  10
+
 #define DSI_0_STRING           ":0:"
 #define DSI_0_STRING_LEN       3
 #define DSI_1_STRING           ":1:"
 #define DSI_1_STRING_LEN       3
 
+#define DSI_CFG_STRING         ":cfg:"
+#define DSI_CFG_STRING_LEN	5
+
+#define DSI_PLL0_STRING         ":pll0"
+#define DSI_PLL1_STRING         ":pll1"
+
 #define NO_PANEL_CONFIG "none"
 #define SIM_VIDEO_PANEL "sim_video_panel"
 #define SIM_DUALDSI_VIDEO_PANEL "sim_dualdsi_video_panel"
diff --git a/dev/gcdb/display/include/panel_nt35597_wqxga_dualdsi_cmd.h b/dev/gcdb/display/include/panel_nt35597_wqxga_dualdsi_cmd.h
index b2bf27f..b01752a 100644
--- a/dev/gcdb/display/include/panel_nt35597_wqxga_dualdsi_cmd.h
+++ b/dev/gcdb/display/include/panel_nt35597_wqxga_dualdsi_cmd.h
@@ -230,7 +230,7 @@
 /* Panel timing                                                              */
 /*---------------------------------------------------------------------------*/
 static const uint32_t nt35597_wqxga_dualdsi_cmd_timings[] = {
-	0xe2, 0x36, 0x24, 0x00, 0x66, 0x6a, 0x28, 0x38,  0x2a, 0x03, 0x04, 0x00
+	0xd5, 0x32, 0x22, 0x00, 0x60, 0x64, 0x26, 0x36, 0x29, 0x03, 0x04, 0x00
 };
 
 static const uint32_t nt35597_wqxga_dualdsi_thulium_cmd_timings[] = {
diff --git a/dev/pmic/pm8x41/include/pm8x41_hw.h b/dev/pmic/pm8x41/include/pm8x41_hw.h
index 0a8e2e8..2bae818 100644
--- a/dev/pmic/pm8x41/include/pm8x41_hw.h
+++ b/dev/pmic/pm8x41/include/pm8x41_hw.h
@@ -94,6 +94,9 @@
 /* USB Peripheral registers */
 #define SMBCHGL_USB_ICL_STS_2                 0x1309
 
+/* PMI8950 slave id */
+#define PMI8950_SLAVE_ID 0x20000
+
 /* USB Peripheral register bits */
 #define USBIN_ACTIVE_PWR_SRC                  BIT(0)
 #define DCIN_ACTIVE_PWR_SRC                   BIT(1)
diff --git a/dev/pmic/pm8x41/pm8x41.c b/dev/pmic/pm8x41/pm8x41.c
index 6733656..0a43bff 100644
--- a/dev/pmic/pm8x41/pm8x41.c
+++ b/dev/pmic/pm8x41/pm8x41.c
@@ -545,7 +545,7 @@
 {
 	uint8_t pon_reason = 0;
 
-	pon_reason = REG_READ(SMBCHGL_USB_ICL_STS_2);
+	pon_reason = REG_READ(SMBCHGL_USB_ICL_STS_2|PMI8950_SLAVE_ID);
 	/* check usbin/dcin status on pmi and set the corresponding bits for pon */
 	pon_reason = (pon_reason & (USBIN_ACTIVE_PWR_SRC|DCIN_ACTIVE_PWR_SRC)) << 3 ;
 	pon_reason |= REG_READ(PON_PON_REASON1);
diff --git a/dev/qpnp_wled/include/qpnp_wled.h b/dev/qpnp_wled/include/qpnp_wled.h
index a04680d..dcd4a8a 100644
--- a/dev/qpnp_wled/include/qpnp_wled.h
+++ b/dev/qpnp_wled/include/qpnp_wled.h
@@ -58,6 +58,7 @@
 #define QPNP_WLED_ILIM_MAX_MA                  1980
 #define QPNP_WLED_ILIM_STEP_MA                 280
 #define QPNP_WLED_DFLT_ILIM_MA                 980
+#define QPNP_WLED_ILIM_OVERWRITE               0x80
 #define QPNP_WLED_BOOST_DUTY_MASK              0xFC
 #define QPNP_WLED_BOOST_DUTY_STEP_NS           52
 #define QPNP_WLED_BOOST_DUTY_MIN_NS            26
diff --git a/dev/qpnp_wled/qpnp_wled.c b/dev/qpnp_wled/qpnp_wled.c
index a0e101d..0ae44a3 100644
--- a/dev/qpnp_wled/qpnp_wled.c
+++ b/dev/qpnp_wled/qpnp_wled.c
@@ -223,9 +223,13 @@
 
 	reg = pm8x41_wled_reg_read(
 			QPNP_WLED_ILIM_REG(wled->ctrl_base));
-	reg &= QPNP_WLED_ILIM_MASK;
-	reg |= (wled->ilim_ma / QPNP_WLED_ILIM_STEP_MA);
-	pm8x41_wled_reg_write(QPNP_WLED_ILIM_REG(wled->ctrl_base), reg);
+	temp = (wled->ilim_ma / QPNP_WLED_ILIM_STEP_MA);
+	if (temp != (reg & ~QPNP_WLED_ILIM_MASK)) {
+		reg &= QPNP_WLED_ILIM_MASK;
+		reg |= temp;
+		reg |= QPNP_WLED_ILIM_OVERWRITE;
+		pm8x41_wled_reg_write(QPNP_WLED_ILIM_REG(wled->ctrl_base), reg);
+	}
 
 	/* Configure the MAX BOOST DUTY register */
 	if (wled->boost_duty_ns < QPNP_WLED_BOOST_DUTY_MIN_NS)
diff --git a/platform/mdmfermium/acpuclock.c b/platform/mdmfermium/acpuclock.c
new file mode 100644
index 0000000..7463222
--- /dev/null
+++ b/platform/mdmfermium/acpuclock.c
@@ -0,0 +1,47 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <err.h>
+#include <assert.h>
+#include <debug.h>
+#include <reg.h>
+#include <platform/timer.h>
+#include <platform/iomap.h>
+#include <clock.h>
+#include <platform/clock.h>
+#include <platform.h>
+
+void hsusb_clock_init(void)
+{
+
+}
+
+/* Configure UART clock based on the UART block id*/
+void clock_config_uart_dm(uint8_t id)
+{
+
+}
diff --git a/platform/mdmfermium/gpio.c b/platform/mdmfermium/gpio.c
new file mode 100644
index 0000000..fba2c76
--- /dev/null
+++ b/platform/mdmfermium/gpio.c
@@ -0,0 +1,77 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <reg.h>
+#include <platform/iomap.h>
+#include <platform/gpio.h>
+#include <blsp_qup.h>
+
+void gpio_tlmm_config(uint32_t gpio, uint8_t func,
+			uint8_t dir, uint8_t pull,
+			uint8_t drvstr, uint32_t enable)
+{
+	uint32_t val = 0;
+
+	val |= pull;
+	val |= func << 2;
+	val |= drvstr << 6;
+	val |= enable << 9;
+
+	writel(val, (uint32_t *)GPIO_CONFIG_ADDR(gpio));
+	return;
+}
+
+void gpio_set_dir(uint32_t gpio, uint32_t dir)
+{
+	writel(dir, (uint32_t *)GPIO_IN_OUT_ADDR(gpio));
+
+	return;
+}
+
+uint32_t gpio_get_state(uint32_t gpio)
+{
+	return readl(GPIO_IN_OUT_ADDR(gpio));
+}
+
+uint32_t gpio_status(uint32_t gpio)
+{
+	return readl(GPIO_IN_OUT_ADDR(gpio)) & GPIO_IN;
+}
+
+/* Configure gpio for blsp uart 2 */
+void gpio_config_uart_dm(uint8_t id)
+{
+	/* configure rx gpio */
+	gpio_tlmm_config(5, 2, GPIO_INPUT, GPIO_NO_PULL,
+				GPIO_8MA, GPIO_DISABLE);
+
+	/* configure tx gpio */
+	gpio_tlmm_config(4, 2, GPIO_OUTPUT, GPIO_NO_PULL,
+				GPIO_8MA, GPIO_DISABLE);
+}
diff --git a/platform/mdmfermium/include/platform/clock.h b/platform/mdmfermium/include/platform/clock.h
new file mode 100644
index 0000000..e3811ff
--- /dev/null
+++ b/platform/mdmfermium/include/platform/clock.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MDMFERMIUM_CLOCK_H
+#define __MDMFERMIUM_CLOCK_H
+
+#include <clock.h>
+#include <clock_lib2.h>
+
+#define UART_DM_CLK_RX_TX_BIT_RATE 0xCC
+
+void platform_clock_init(void);
+
+void clock_config_uart_dm(uint8_t id);
+void hsusb_clock_init(void);
+#endif
diff --git a/platform/mdmfermium/include/platform/gpio.h b/platform/mdmfermium/include/platform/gpio.h
new file mode 100644
index 0000000..aa3a38e
--- /dev/null
+++ b/platform/mdmfermium/include/platform/gpio.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PLATFORM_MDMFERMIUM_GPIO_H
+#define __PLATFORM_MDMFERMIUM_GPIO_H
+
+#include <bits.h>
+#include <gpio.h>
+
+/* GPIO TLMM: Direction */
+#define GPIO_INPUT      0
+#define GPIO_OUTPUT     1
+
+/* GPIO TLMM: Pullup/Pulldown */
+#define GPIO_NO_PULL    0
+#define GPIO_PULL_DOWN  1
+#define GPIO_KEEPER     2
+#define GPIO_PULL_UP    3
+
+/* GPIO TLMM: Drive Strength */
+#define GPIO_2MA        0
+#define GPIO_4MA        1
+#define GPIO_6MA        2
+#define GPIO_8MA        3
+#define GPIO_10MA       4
+#define GPIO_12MA       5
+#define GPIO_14MA       6
+#define GPIO_16MA       7
+
+/* GPIO TLMM: Status */
+#define GPIO_ENABLE     0
+#define GPIO_DISABLE    1
+
+/* GPIO_IN_OUT register shifts. */
+#define GPIO_IN         BIT(0)
+#define GPIO_OUT        BIT(1)
+
+void gpio_config_uart_dm(uint8_t id);
+uint32_t gpio_status(uint32_t gpio);
+void gpio_set_dir(uint32_t gpio, uint32_t dir);
+void gpio_tlmm_config(uint32_t gpio,
+			uint8_t func,
+			uint8_t dir,
+			uint8_t pull,
+			uint8_t drvstr,
+			uint32_t enable);
+#endif
diff --git a/platform/mdmfermium/include/platform/iomap.h b/platform/mdmfermium/include/platform/iomap.h
new file mode 100644
index 0000000..852e5a9
--- /dev/null
+++ b/platform/mdmfermium/include/platform/iomap.h
@@ -0,0 +1,112 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PLATFORM_MDMFERMIUM_IOMAP_H_
+#define _PLATFORM_MDMFERMIUM_IOMAP_H_
+
+#define MSM_IOMAP_BASE                     0x00000000
+#define MSM_IOMAP_END                      0x08000000
+
+#define A7_SS_BASE                 0x0B000000
+#define A7_SS_END                  0x0B200000
+
+#define SDRAM_START_ADDR                   0x80000000
+
+#define SYSTEM_IMEM_BASE                   0x08600000
+#define MSM_SHARED_BASE                    0x87D00000
+#define MSM_SHARED_IMEM_BASE               0x08600000
+
+#define BS_INFO_OFFSET                     (0x6B0)
+#define BS_INFO_ADDR                       (MSM_SHARED_IMEM_BASE + BS_INFO_OFFSET)
+
+#define RESTART_REASON_ADDR                (MSM_SHARED_IMEM_BASE + 0x65C)
+
+#define MSM_NAND_BASE                      0x79B0000
+/* NAND BAM */
+#define MSM_NAND_BAM_BASE           0x7984000
+
+#define APPS_SS_BASE                       0x0B000000
+
+#define MSM_GIC_DIST_BASE                  APPS_SS_BASE
+#define MSM_GIC_CPU_BASE                   (APPS_SS_BASE + 0x2000)
+#define APPS_APCS_QTMR_AC_BASE             (APPS_SS_BASE + 0x00020000)
+#define APPS_APCS_F0_QTMR_V1_BASE          (APPS_SS_BASE + 0x00021000)
+#define APCS_ALIAS0_IPC_INTERRUPT          (APPS_SS_BASE + 0x00011008)
+#define QTMR_BASE                          APPS_APCS_F0_QTMR_V1_BASE
+
+#define PERIPH_SS_BASE                     0x07800000
+
+
+#define BLSP1_UART0_BASE                   (PERIPH_SS_BASE + 0x000AF000)
+#define BLSP1_UART1_BASE                   (PERIPH_SS_BASE + 0x000B0000)
+#define MSM_USB_BASE                       (PERIPH_SS_BASE + 0x000D9000)
+
+#define CLK_CTL_BASE                       0x1800000
+
+#define SPMI_BASE                          0x02000000
+#define SPMI_GENI_BASE                     (SPMI_BASE + 0xA000)
+#define SPMI_PIC_BASE                      (SPMI_BASE +  0x01800000)
+#define PMIC_ARB_CORE                      0x200F000
+
+#define TLMM_BASE_ADDR                     0x1000000
+#define GPIO_CONFIG_ADDR(x)                (TLMM_BASE_ADDR + (x)*0x1000)
+#define GPIO_IN_OUT_ADDR(x)                (TLMM_BASE_ADDR + 0x00000004 + (x)*0x1000)
+
+#define MPM2_MPM_CTRL_BASE                 0x004A0000
+#define MPM2_MPM_PS_HOLD                   0x004AB000
+#define MPM2_MPM_SLEEP_TIMETICK_COUNT_VAL  0x004A3000
+
+/* CRYPTO ENGINE */
+#define  MSM_CE1_BASE                      0x073A000
+#define  MSM_CE1_BAM_BASE                  0x0704000
+
+
+/* GPLL */
+#define GPLL0_STATUS                       (CLK_CTL_BASE + 0x21024)
+#define APCS_GPLL_ENA_VOTE                 (CLK_CTL_BASE + 0x45000)
+#define APCS_CLOCK_BRANCH_ENA_VOTE         (CLK_CTL_BASE + 0x45004)
+
+/* UART */
+#define BLSP1_AHB_CBCR                     (CLK_CTL_BASE + 0x1008)
+#define BLSP1_UART2_APPS_CBCR              (CLK_CTL_BASE + 0x302C)
+#define BLSP1_UART2_APPS_CMD_RCGR          (CLK_CTL_BASE + 0x3034)
+#define BLSP1_UART2_APPS_CFG_RCGR          (CLK_CTL_BASE + 0x3038)
+#define BLSP1_UART2_APPS_M                 (CLK_CTL_BASE + 0x303C)
+#define BLSP1_UART2_APPS_N                 (CLK_CTL_BASE + 0x3040)
+#define BLSP1_UART2_APPS_D                 (CLK_CTL_BASE + 0x3044)
+
+/* USB */
+#define USB_HS_BCR                         (CLK_CTL_BASE + 0x41000)
+#define USB_HS_SYSTEM_CBCR                 (CLK_CTL_BASE + 0x41004)
+#define USB_HS_AHB_CBCR                    (CLK_CTL_BASE + 0x41008)
+#define USB_HS_SYSTEM_CMD_RCGR             (CLK_CTL_BASE + 0x41010)
+#define USB_HS_SYSTEM_CFG_RCGR             (CLK_CTL_BASE + 0x41014)
+
+#define TCSR_TZ_WONCE               0x193D000
+#define TCSR_BOOT_MISC_DETECT       0x193D100
+#endif
diff --git a/platform/mdmfermium/include/platform/irqs.h b/platform/mdmfermium/include/platform/irqs.h
new file mode 100644
index 0000000..8738b97
--- /dev/null
+++ b/platform/mdmfermium/include/platform/irqs.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __IRQS_MDMFERMIUM_H
+#define __IRQS_MDMFERMIUM_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/* 0-15:  STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+:   SPI (shared peripheral interrupts)
+ */
+
+#define GIC_PPI_START                          16
+#define GIC_SPI_START                          32
+
+#define INT_QTMR_NON_SECURE_PHY_TIMER_EXP      (GIC_PPI_START + 3)
+#define INT_QTMR_VIRTUAL_TIMER_EXP             (GIC_PPI_START + 4)
+
+#define INT_QTMR_FRM_0_PHYSICAL_TIMER_EXP      (GIC_SPI_START + 7)
+
+#define USB1_HS_BAM_IRQ                        (GIC_SPI_START + 135)
+#define USB1_HS_IRQ                            (GIC_SPI_START + 134)
+
+/* Retrofit universal macro names */
+#define INT_USB_HS                             USB1_HS_IRQ
+
+#define EE0_KRAIT_HLOS_SPMI_PERIPH_IRQ         (GIC_SPI_START + 190)
+
+#define SMD_IRQ                                (GIC_SPI_START + 168)
+
+#define NR_MSM_IRQS                            256
+#define NR_GPIO_IRQS                           173
+#define NR_BOARD_IRQS                          0
+
+#define NR_IRQS                                (NR_MSM_IRQS + NR_GPIO_IRQS + \
+                                               NR_BOARD_IRQS)
+
+#endif /* __IRQS_MDMFERMIUM_H */
diff --git a/platform/mdmfermium/mdmfermium-clock.c b/platform/mdmfermium/mdmfermium-clock.c
new file mode 100644
index 0000000..235d40f
--- /dev/null
+++ b/platform/mdmfermium/mdmfermium-clock.c
@@ -0,0 +1,233 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <reg.h>
+#include <err.h>
+#include <clock.h>
+#include <clock_pll.h>
+#include <clock_lib2.h>
+#include <platform/clock.h>
+#include <platform/iomap.h>
+#include <platform.h>
+
+/* Mux source select values */
+#define cxo_source_val    0
+#define gpll0_source_val  1
+#define gpll4_source_val  2
+#define cxo_mm_source_val 0
+#define gpll0_mm_source_val 1
+
+struct clk_freq_tbl rcg_dummy_freq = F_END;
+
+
+/* Clock Operations */
+static struct clk_ops clk_ops_branch =
+{
+	.enable     = clock_lib2_branch_clk_enable,
+	.disable    = clock_lib2_branch_clk_disable,
+	.set_rate   = clock_lib2_branch_set_rate,
+};
+
+static struct clk_ops clk_ops_rcg_mnd =
+{
+	.enable     = clock_lib2_rcg_enable,
+	.set_rate   = clock_lib2_rcg_set_rate,
+};
+
+static struct clk_ops clk_ops_rcg =
+{
+	.enable     = clock_lib2_rcg_enable,
+	.set_rate   = clock_lib2_rcg_set_rate,
+};
+
+static struct clk_ops clk_ops_cxo =
+{
+	.enable     = cxo_clk_enable,
+	.disable    = cxo_clk_disable,
+};
+
+static struct clk_ops clk_ops_pll_vote =
+{
+	.enable     = pll_vote_clk_enable,
+	.disable    = pll_vote_clk_disable,
+	.auto_off   = pll_vote_clk_disable,
+	.is_enabled = pll_vote_clk_is_enabled,
+};
+
+static struct clk_ops clk_ops_vote =
+{
+	.enable     = clock_lib2_vote_clk_enable,
+	.disable    = clock_lib2_vote_clk_disable,
+};
+
+/* Clock Sources */
+static struct fixed_clk cxo_clk_src =
+{
+	.c = {
+		.rate     = 19200000,
+		.dbg_name = "cxo_clk_src",
+		.ops      = &clk_ops_cxo,
+	},
+};
+
+static struct pll_vote_clk gpll0_clk_src =
+{
+	.en_reg       = (void *) APCS_GPLL_ENA_VOTE,
+	.en_mask      = BIT(0),
+	.status_reg   = (void *) GPLL0_STATUS,
+	.status_mask  = BIT(17),
+	.parent       = &cxo_clk_src.c,
+
+	.c = {
+		.rate     = 800000000,
+		.dbg_name = "gpll0_clk_src",
+		.ops      = &clk_ops_pll_vote,
+	},
+};
+
+/* UART Clocks */
+static struct clk_freq_tbl ftbl_gcc_blsp1_2_uart1_2_apps_clk[] =
+{
+	F( 3686400,  gpll0,    1,  72,  15625),
+	F( 7372800,  gpll0,    1, 144,  15625),
+	F(14745600,  gpll0,    1, 288,  15625),
+	F(16000000,  gpll0,   10,   1,      5),
+	F(19200000,    cxo,    1,   0,      0),
+	F(24000000,  gpll0,    1,   3,    100),
+	F(25000000,  gpll0,   16,   1,      2),
+	F(32000000,  gpll0,    1,   1,     25),
+	F(40000000,  gpll0,    1,   1,     20),
+	F(46400000,  gpll0,    1,  29,    500),
+	F(48000000,  gpll0,    1,   3,     50),
+	F(51200000,  gpll0,    1,   8,    125),
+	F(56000000,  gpll0,    1,   7,    100),
+	F(58982400,  gpll0,    1,1152,  15625),
+	F(60000000,  gpll0,    1,   3,     40),
+	F_END
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src =
+{
+	.cmd_reg      = (uint32_t *) BLSP1_UART2_APPS_CMD_RCGR,
+	.cfg_reg      = (uint32_t *) BLSP1_UART2_APPS_CFG_RCGR,
+	.m_reg        = (uint32_t *) BLSP1_UART2_APPS_M,
+	.n_reg        = (uint32_t *) BLSP1_UART2_APPS_N,
+	.d_reg        = (uint32_t *) BLSP1_UART2_APPS_D,
+
+	.set_rate     = clock_lib2_rcg_set_rate_mnd,
+	.freq_tbl     = ftbl_gcc_blsp1_2_uart1_2_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+
+	.c = {
+		.dbg_name = "blsp1_uart2_apps_clk",
+		.ops      = &clk_ops_rcg_mnd,
+	},
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk =
+{
+	.cbcr_reg     = (uint32_t *) BLSP1_UART2_APPS_CBCR,
+	.parent       = &blsp1_uart2_apps_clk_src.c,
+
+	.c = {
+		.dbg_name = "gcc_blsp1_uart2_apps_clk",
+		.ops      = &clk_ops_branch,
+	},
+};
+
+static struct vote_clk gcc_blsp1_ahb_clk = {
+	.cbcr_reg     = (uint32_t *) BLSP1_AHB_CBCR,
+	.vote_reg     = (uint32_t *) APCS_CLOCK_BRANCH_ENA_VOTE,
+	.en_mask      = BIT(10),
+
+	.c = {
+		.dbg_name = "gcc_blsp1_ahb_clk",
+		.ops      = &clk_ops_vote,
+	},
+};
+
+/* USB Clocks */
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk[] =
+{
+	F(133330000,  gpll0,    6,   0,   0),
+	F_END
+};
+
+static struct rcg_clk usb_hs_system_clk_src =
+{
+	.cmd_reg      = (uint32_t *) USB_HS_SYSTEM_CMD_RCGR,
+	.cfg_reg      = (uint32_t *) USB_HS_SYSTEM_CFG_RCGR,
+
+	.set_rate     = clock_lib2_rcg_set_rate_hid,
+	.freq_tbl     = ftbl_gcc_usb_hs_system_clk,
+	.current_freq = &rcg_dummy_freq,
+
+	.c = {
+		.dbg_name = "usb_hs_system_clk",
+		.ops      = &clk_ops_rcg,
+	},
+};
+
+static struct branch_clk gcc_usb_hs_system_clk =
+{
+	.cbcr_reg     = (uint32_t *) USB_HS_SYSTEM_CBCR,
+	.parent       = &usb_hs_system_clk_src.c,
+
+	.c = {
+		.dbg_name = "gcc_usb_hs_system_clk",
+		.ops      = &clk_ops_branch,
+	},
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk =
+{
+	.cbcr_reg     = (uint32_t *) USB_HS_AHB_CBCR,
+	.has_sibling  = 1,
+
+	.c = {
+		.dbg_name = "gcc_usb_hs_ahb_clk",
+		.ops      = &clk_ops_branch,
+	},
+};
+
+/* Clock lookup table */
+static struct clk_lookup mdm_clocks_fermium[] =
+{
+	CLK_LOOKUP("uart2_iface_clk", gcc_blsp1_ahb_clk.c),
+	CLK_LOOKUP("uart2_core_clk",  gcc_blsp1_uart2_apps_clk.c),
+
+	CLK_LOOKUP("usb_iface_clk",  gcc_usb_hs_ahb_clk.c),
+	CLK_LOOKUP("usb_core_clk",   gcc_usb_hs_system_clk.c),
+
+};
+
+void platform_clock_init(void)
+{
+	clk_init(mdm_clocks_fermium, ARRAY_SIZE(mdm_clocks_fermium));
+}
diff --git a/platform/mdmfermium/platform.c b/platform/mdmfermium/platform.c
new file mode 100644
index 0000000..7d05f04
--- /dev/null
+++ b/platform/mdmfermium/platform.c
@@ -0,0 +1,69 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <reg.h>
+#include <platform/iomap.h>
+#include <qgic.h>
+#include <qtimer.h>
+#include <mmu.h>
+#include <arch/arm/mmu.h>
+#include <smem.h>
+
+void platform_early_init(void)
+{
+	qgic_init();
+	qtimer_init();
+//	scm_init();
+}
+
+void platform_init(void)
+{
+	dprintf(INFO, "platform_init()\n");
+}
+
+void platform_uninit(void)
+{
+	qtimer_uninit();
+}
+
+uint32_t platform_get_sclk_count(void)
+{
+	return readl(MPM2_MPM_SLEEP_TIMETICK_COUNT_VAL);
+}
+
+addr_t get_bs_info_addr()
+{
+	return ((addr_t)BS_INFO_ADDR);
+}
+
+int platform_use_identity_mmu_mappings(void)
+{
+	/* Use only the mappings specified in this file. */
+	return 1;
+}
diff --git a/platform/mdmfermium/rules.mk b/platform/mdmfermium/rules.mk
new file mode 100644
index 0000000..d5f789a
--- /dev/null
+++ b/platform/mdmfermium/rules.mk
@@ -0,0 +1,23 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+ARCH    := arm
+ARM_CPU := cortex-a8
+CPU     := generic
+
+DEFINES += ARM_CPU_CORE_A7
+
+
+DEFINES += PERIPH_BLK_BLSP=1
+DEFINES += WITH_CPU_EARLY_INIT=0 WITH_CPU_WARM_BOOT=0
+
+INCLUDES += -I$(LOCAL_DIR)/include -I$(LK_TOP_DIR)/platform/msm_shared/include
+
+OBJS += \
+       $(LOCAL_DIR)/platform.o \
+       $(LOCAL_DIR)/acpuclock.o \
+       $(LOCAL_DIR)/gpio.o \
+       $(LOCAL_DIR)/mdmfermium-clock.o
+
+LINKER_SCRIPT += $(BUILDDIR)/system-onesegment.ld
+
+include platform/msm_shared/rules.mk
diff --git a/platform/msm8996/include/platform/iomap.h b/platform/msm8996/include/platform/iomap.h
index 2244632..ea2a0bf 100644
--- a/platform/msm8996/include/platform/iomap.h
+++ b/platform/msm8996/include/platform/iomap.h
@@ -161,7 +161,7 @@
 
 /* QSEECOM: Secure app region notification */
 #define APP_REGION_ADDR 0x86600000
-#define APP_REGION_SIZE 0xd00000
+#define APP_REGION_SIZE 0x2200000
 
 /* DRV strength for sdcc */
 #define SDC1_HDRV_PULL_CTL           (TLMM_BASE_ADDR + 0x0012C000)
@@ -527,9 +527,4 @@
 #define QPNP_GREEN_LPG_CTRL_BASE    0xB200
 #define QPNP_RED_LPG_CTRL_BASE      0xB300
 
-#define APSS_WDOG_BASE              0x9830000
-#define APPS_WDOG_BARK_VAL_REG      (APSS_WDOG_BASE + 0x10)
-#define APPS_WDOG_BITE_VAL_REG      (APSS_WDOG_BASE + 0x14)
-#define APPS_WDOG_RESET_REG         (APSS_WDOG_BASE + 0x04)
-#define APPS_WDOG_CTL_REG           (APSS_WDOG_BASE + 0x08)
 #endif
diff --git a/platform/msm8996/platform.c b/platform/msm8996/platform.c
index 6e04abf..8bdfff0 100644
--- a/platform/msm8996/platform.c
+++ b/platform/msm8996/platform.c
@@ -36,6 +36,7 @@
 #include <mmu.h>
 #include <smem.h>
 #include <board.h>
+#include <target/display.h>
 
 #define MSM_IOMAP_SIZE     ((MSM_IOMAP_END - MSM_IOMAP_BASE)/MB)
 #define MSM_SHARED_SIZE    2
@@ -60,8 +61,10 @@
 static mmu_section_t default_mmu_section_table[] =
 {
 /*        Physical addr,    Virtual addr,     Mapping type ,              Size (in MB),            Flags */
-    {    0x00000000,        0x00000000,       MMU_L1_NS_SECTION_MAPPING,  1024,                IOMAP_MEMORY},
-    {    KERNEL_ADDR,       KERNEL_ADDR,      MMU_L2_NS_SECTION_MAPPING,  KERNEL_SIZE,         COMMON_MEMORY},
+    {    0x00000000,        0x00000000,       MMU_L2_NS_SECTION_MAPPING,  512,                IOMAP_MEMORY},
+    {    KERNEL_ADDR,       KERNEL_ADDR,      MMU_L2_NS_SECTION_MAPPING,  KERNEL_SIZE,        COMMON_MEMORY},
+    {    0x40000000,        0x40000000,       MMU_L1_NS_SECTION_MAPPING,  1024       ,        COMMON_MEMORY},
+    {    0x80000000,        0x80000000,       MMU_L2_NS_SECTION_MAPPING,  88         ,        COMMON_MEMORY},
     {    MEMBASE,           MEMBASE,          MMU_L2_NS_SECTION_MAPPING,  (MEMSIZE / MB),      LK_MEMORY},
     {    SCRATCH_ADDR,      SCRATCH_ADDR,     MMU_L2_NS_SECTION_MAPPING,  SCRATCH_SIZE,        SCRATCH_MEMORY},
     {    MSM_SHARED_BASE,   MSM_SHARED_BASE,  MMU_L2_NS_SECTION_MAPPING,  MSM_SHARED_SIZE,     COMMON_MEMORY},
diff --git a/platform/msm_shared/include/mmc_sdhci.h b/platform/msm_shared/include/mmc_sdhci.h
index 6ef404b..54f09ee 100644
--- a/platform/msm_shared/include/mmc_sdhci.h
+++ b/platform/msm_shared/include/mmc_sdhci.h
@@ -89,6 +89,7 @@
 #define MMC_EXT_CSD_RST_N_FUNC                    162
 #define MMC_EXT_MMC_BUS_WIDTH                     183
 #define MMC_EXT_MMC_HS_TIMING                     185
+#define MMC_EXT_CSD_REV                           192
 #define MMC_DEVICE_TYPE                           196
 #define MMC_EXT_MMC_DRV_STRENGTH                  197
 #define MMC_EXT_HC_WP_GRP_SIZE                    221
@@ -102,6 +103,7 @@
 #define MMC_ERASE_TIMEOUT_MULT                    223
 #define MMC_HC_ERASE_GRP_SIZE                     224
 #define MMC_PARTITION_CONFIG                      179
+#define MMC_EXT_CSD_EN_RPMB_REL_WR                166 //emmc 5.1 and above
 
 /* Values for ext csd fields */
 #define MMC_HS_TIMING                             0x1
diff --git a/platform/msm_shared/include/rpmb.h b/platform/msm_shared/include/rpmb.h
index 6cd7ecd..f954dfb 100644
--- a/platform/msm_shared/include/rpmb.h
+++ b/platform/msm_shared/include/rpmb.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -147,15 +147,15 @@
 int write_device_info_rpmb(void *info, uint32_t sz);
 
 /* Function Prototypes */
-int rpmb_write_emmc(struct mmc_device *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
+int rpmb_write_emmc(struct mmc_device *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t rel_wr_count, uint32_t *resp_buf, uint32_t *resp_len);
 int rpmb_read_emmc(struct mmc_device *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
-int rpmb_write_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
+int rpmb_write_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t rel_wr_count, uint32_t *resp_buf, uint32_t *resp_len);
 int rpmb_read_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
 
 /* APIs exposed to applications */
 int rpmb_init();
 int rpmb_uninit();
-int rpmb_write(uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
+int rpmb_write(uint32_t *req_buf, uint32_t blk_cnt, uint32_t rel_wr_count, uint32_t *resp_buf, uint32_t *resp_len);
 int rpmb_read(uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len);
 struct rpmb_init_info *rpmb_get_init_info();
 int rpmb_get_app_handle();
diff --git a/platform/msm_shared/include/sdhci.h b/platform/msm_shared/include/sdhci.h
index c0b484d..64fb2b0 100644
--- a/platform/msm_shared/include/sdhci.h
+++ b/platform/msm_shared/include/sdhci.h
@@ -102,6 +102,7 @@
 	uint64_t cmd_timeout;   /* Command timeout in us */
 	bool write_flag;        /* Write flag, for reliable write cases */
 	struct mmc_data data;   /* Data pointer */
+	uint8_t rel_write;      /* Reliable write enable flag */
 };
 
 /*
diff --git a/platform/msm_shared/rpmb/rpmb.c b/platform/msm_shared/rpmb/rpmb.c
index 36bacab..29d72e3 100644
--- a/platform/msm_shared/rpmb/rpmb.c
+++ b/platform/msm_shared/rpmb/rpmb.c
@@ -50,7 +50,30 @@
 	{
 		struct mmc_device *mmc_dev = (struct mmc_device *) dev;
 		info.size = mmc_dev->card.rpmb_size / RPMB_MIN_BLK_SZ;
-		info.rel_wr_count = mmc_dev->card.rel_wr_count;
+		if (mmc_dev->card.ext_csd[MMC_EXT_CSD_REV] < 8)
+		{
+			dprintf(SPEW, "EMMC Version < 5.1\n");
+			info.rel_wr_count = mmc_dev->card.rel_wr_count;
+		}
+		else
+		{
+			if (mmc_dev->card.ext_csd[MMC_EXT_CSD_EN_RPMB_REL_WR] == 0)
+			{
+				dprintf(SPEW, "EMMC Version >= 5.1 EN_RPMB_REL_WR = 0\n");
+				// according to emmc version 5.1 and above if EN_RPMB_REL_WR in extended
+				// csd is not set the maximum number of frames that can be reliably written
+				// to emmc would be 2
+				info.rel_wr_count = 2;
+			}
+			else
+			{
+				dprintf(SPEW, "EMMC Version >= 5.1 EN_RPMB_REL_WR = 1\n");
+				// according to emmc version 5.1 and above if EN_RPMB_REL_WR in extended
+				// csd is set the maximum number of frames that can be reliably written
+				// to emmc would be 32
+				info.rel_wr_count = 32;
+			}
+		}
 		info.dev_type  = EMMC_RPMB;
 	}
 	else
@@ -105,12 +128,12 @@
 		return rpmb_read_ufs(dev, req, req_len, resp, resp_len);
 }
 
-int rpmb_write(uint32_t *req, uint32_t req_len, uint32_t *resp, uint32_t *resp_len)
+int rpmb_write(uint32_t *req, uint32_t req_len, uint32_t rel_wr_count, uint32_t *resp, uint32_t *resp_len)
 {
 	if (platform_boot_dev_isemmc())
-		return rpmb_write_emmc(dev, req, req_len, resp, resp_len);
+		return rpmb_write_emmc(dev, req, req_len, rel_wr_count, resp, resp_len);
 	else
-		return rpmb_write_ufs(dev, req, req_len, resp, resp_len);
+		return rpmb_write_ufs(dev, req, req_len, rel_wr_count, resp, resp_len);
 }
 
 /* This API calls into TZ app to read device_info */
diff --git a/platform/msm_shared/rpmb/rpmb_emmc.c b/platform/msm_shared/rpmb/rpmb_emmc.c
index 2bfa545..3b00e09 100644
--- a/platform/msm_shared/rpmb/rpmb_emmc.c
+++ b/platform/msm_shared/rpmb/rpmb_emmc.c
@@ -47,17 +47,36 @@
 	.requestresponse[1] = READ_RESULT_FLAG,
 };
 
-int rpmb_write_emmc(struct mmc_device *dev,uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len)
+int rpmb_write_emmc(struct mmc_device *dev,uint32_t *req_buf, uint32_t blk_cnt, uint32_t rel_wr_count, uint32_t *resp_buf, uint32_t *resp_len)
 {
-	uint32_t i;
+	uint32_t i, num_trans;
 	int ret = 0;
 	struct mmc_command cmd[3] = {{0},{0},{0}};
 	struct rpmb_frame *result = (struct rpmb_frame *)resp_buf;
 
-	for (i = 0; i < blk_cnt; i++)
+	dprintf(INFO, "rpmb write command called with blk_cnt: 0x%x\n", blk_cnt);
+	if (rel_wr_count == 0x2)
+	{
+		// if reliable write count reported by secure app is 2 then we can
+		// send two half sectors in one transaction. So overall number of
+		// transactions would be total block count by 2.
+		num_trans = blk_cnt / 2;
+	}
+	else if(rel_wr_count == 0x1)
+	{
+		num_trans = blk_cnt; // rel_rw_count = 1 for emmc 5.0 and below
+	}
+	else
+	{
+		dprintf(CRITICAL, "Reliable write count > 2 is not supported\n");
+		return -1;
+	}
+
+	for (i = 0; i < num_trans; i++)
 	{
 #if DEBUG_RPMB
-		dump_rpmb_frame((uint8_t *)req_buf, "request");
+		for(uint8_t j = 0; j < rel_wr_count; j++)
+			dump_rpmb_frame((uint8_t *)req_buf + (j * 512), "request");
 #endif
 
 		/* CMD25 program data packet */
@@ -69,8 +88,16 @@
 		cmd[0].trans_mode = SDHCI_MMC_WRITE;
 		cmd[0].data_present = 0x1;
 		cmd[0].data.data_ptr = (void *)req_buf;
-		cmd[0].data.num_blocks = RPMB_MIN_BLK_CNT;
-
+		if (rel_wr_count == 0x1)
+		{
+			cmd[0].rel_write = 0;
+			cmd[0].data.num_blocks = RPMB_MIN_BLK_CNT;
+		}
+		else if(rel_wr_count == 0x2)
+		{
+			cmd[0].rel_write = 1;
+			cmd[0].data.num_blocks = 0x2;
+		}
 		/* CMD25 Result Register Read Request Packet */
 		cmd[1].write_flag = false;
 		cmd[1].cmd_index = CMD25_WRITE_MULTIPLE_BLOCK;
@@ -101,6 +128,9 @@
 			break;
 		}
 
+#if DEBUG_RPMB
+		dump_rpmb_frame((uint8_t *)resp_buf, "response");
+#endif
 		if (result->result[0] == 0x80)
 		{
 			dprintf(CRITICAL, "Max write counter reached: \n");
@@ -112,12 +142,11 @@
 			dprintf(CRITICAL, "%s\n", str_err[result->result[1]]);
 			break;
 		}
+		if (rel_wr_count == 0x1)
+			req_buf = (uint32_t*) ((uint8_t*)req_buf + (RPMB_BLK_SIZE));
+		else if(rel_wr_count == 0x2)
+			req_buf = (uint32_t*) ((uint8_t*)req_buf + (RPMB_BLK_SIZE * 0x2));
 
-		req_buf = (uint32_t*) ((uint8_t*)req_buf + RPMB_BLK_SIZE);
-
-#if DEBUG_RPMB
-		dump_rpmb_frame((uint8_t *)resp_buf, "response");
-#endif
 	}
 	*resp_len = RPMB_MIN_BLK_CNT * RPMB_BLK_SIZE;
 
diff --git a/platform/msm_shared/rpmb/rpmb_listener.c b/platform/msm_shared/rpmb/rpmb_listener.c
index 7cf0b79..c9623e2 100644
--- a/platform/msm_shared/rpmb/rpmb_listener.c
+++ b/platform/msm_shared/rpmb/rpmb_listener.c
@@ -67,6 +67,8 @@
 	uint32_t num_sectors;
 	uint32_t req_buff_len;
 	uint32_t req_buff_offset;
+	uint32_t version;
+	uint32_t rel_wr_count;
 }__PACKED;
 
 struct tz_rpmb_rw_resp
@@ -75,6 +77,7 @@
 	int32_t  status;
 	uint32_t res_buff_len;
 	uint32_t res_buff_offset;
+	uint32_t version;
 }__PACKED;
 
 typedef int (*ListenerCallback)(void*, uint32_t);
@@ -113,14 +116,16 @@
 		case TZ_CM_CMD_RPMB_READ:
 #if DEBUG_RPMB
 			dprintf(INFO, "Read Request received\n");
+			dprintf(INFO, "READ: RPMB_REL_RW_COUNT 0x%x\n", req_p->rel_wr_count);
 #endif
 			resp_p->status = rpmb_read(req_buf, req_p->num_sectors, resp_buf, &resp_p->res_buff_len);
 			break;
 		case TZ_CM_CMD_RPMB_WRITE:
 #if DEBUG_RPMB
 			dprintf(INFO, "Write Request received\n");
+			dprintf(INFO, "WRITE: RPMB_REL_RW_COUNT 0x%x\n", req_p->rel_wr_count);
 #endif
-			resp_p->status = rpmb_write(req_buf, req_p->num_sectors, resp_buf, &resp_p->res_buff_len);
+			resp_p->status = rpmb_write(req_buf, req_p->num_sectors, req_p->rel_wr_count, resp_buf, &resp_p->res_buff_len);
 			break;
 		default:
 			dprintf(CRITICAL, "Unsupported request command request: %u\n", req_p->cmd_id);
@@ -174,7 +179,7 @@
 
 	rpmb_listener.service_name = "RPMB system services";
 	rpmb_listener.id           =  RPMB_LSTNR_ID;
-	rpmb_listener.sb_size      = 20 * 1024;
+	rpmb_listener.sb_size      = 25 * 1024;
 	rpmb_listener.service_cmd_handler = rpmb_cmd_handler;
 
 	ret = qseecom_register_listener(&rpmb_listener);
diff --git a/platform/msm_shared/rpmb/rpmb_ufs.c b/platform/msm_shared/rpmb/rpmb_ufs.c
index 3cc4d91..17cfc56 100644
--- a/platform/msm_shared/rpmb/rpmb_ufs.c
+++ b/platform/msm_shared/rpmb/rpmb_ufs.c
@@ -36,6 +36,18 @@
 #include <endian.h>
 #include <arch/defines.h>
 
+static const char *str_err[] =
+{
+	"Operation Ok",
+	"General failure",
+	"Authentication error (MAC comparison not matching, MAC calculation failure)",
+	"Counter failure (counters not matching in comparison, counter incrementing failure)",
+	"Address failure (address out of range, wrong address alignment)",
+	"Write failure (data/counter/result write failure)",
+	"Read failure (data/counter/result read failure)",
+	"Authentication Key not yet programmed",
+};
+
 static struct rpmb_frame read_result_reg =
 {
 	.requestresponse[1] = READ_RESULT_FLAG,
@@ -71,8 +83,8 @@
 		return -UFS_FAILURE;
 	}
 #ifdef DEBUG_RPMB
-	dprintf(SPEW, "rpmb_read: req_buf: 0x%x blk_count: 0x%x\n", *req_buf, blk_cnt);
-	dprintf(INFO, "rpmb_read: bytes_to_transfer: 0x%x blks_to_transfer: 0x%x\n",
+	dprintf(INFO, "rpmb_read: req_buf: 0x%x blk_count: 0x%x\n", *req_buf, blk_cnt);
+	dprintf(INFO, "rpmb_read: bytes_to_transfer: 0x%llx blks_to_transfer: 0x%x\n",
                    bytes_to_transfer, blks_to_transfer);
 #endif
 	// send the request
@@ -138,15 +150,18 @@
 		dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
 		return -UFS_FAILURE;
 	}
+	// invalidate response buffer before reading response as this is part of request
+	// buffer overwritten
+	arch_clean_invalidate_cache_range((addr_t) resp_buf, RPMB_FRAME_SIZE);
 #ifdef DEBUG_RPMB
-	dprintf(SPEW, "Sending RPMB Read response complete\n");
+	dprintf(INFO, "Sending RPMB Read response complete\n");
 	dump_rpmb_frame((uint8_t *)resp_buf, "response");
 #endif
 	*resp_len = bytes_to_transfer;
 	return UFS_SUCCESS;
 }
 
-int rpmb_write_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len)
+int rpmb_write_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t rel_wr_count, uint32_t *resp_buf, uint32_t *resp_len)
 {
 	// validate input parameters
 	ASSERT(req_buf);
@@ -156,12 +171,14 @@
 	STACKBUF_DMA_ALIGN(cdb, sizeof(struct scsi_sec_protocol_cdb));
 	struct scsi_req_build_type   req_upiu;
 	struct scsi_sec_protocol_cdb *cdb_out_param, *cdb_in_param;
+	struct rpmb_frame *result = (struct rpmb_frame *)resp_buf;
 	uint32_t                     blks_remaining;
 	uint32_t                     blks_to_transfer;
 	uint64_t                     bytes_to_transfer;
 	uint64_t                     max_size;
 	uint32_t                     result_frame_bytes = RPMB_FRAME_SIZE;
 	uint32_t                     i;
+	uint32_t                     num_trans;
 
 	blks_remaining    = blk_cnt;
 	blks_to_transfer  = blks_remaining;
@@ -176,13 +193,31 @@
 	}
 #ifdef DEBUG_RPMB
 	dprintf(INFO, "%s: req_buf: 0x%x blk_count: 0x%x\n", __func__,*req_buf, blk_cnt);
-	dprintf(INFO, "%s: bytes_to_transfer: 0x%x blks_to_transfer: 0x%x\n", __func__
-                   bytes_to_transfer, blk_cnt);
-	dump_rpmb_frame((uint8_t *)req_buf, "request");
+	dprintf(INFO, "%s: bytes_to_transfer: 0x%llx blks_to_transfer: 0x%x\n", __func__, bytes_to_transfer, blk_cnt);
 #endif
-
-	for (i = 0; i < blk_cnt; i++)
+	if (bytes_to_transfer <= (rel_wr_count * RPMB_FRAME_SIZE))
 	{
+		num_trans = 1;
+	}
+	else
+	{
+		// send uptop rel_wr_count number of frames in one shot + anything pending
+		num_trans = blk_cnt/rel_wr_count;
+		if (num_trans % rel_wr_count) // if anymore frames still pending
+			num_trans++;
+	}
+	for (i = 0; i < num_trans; i++)
+	{
+		if ((num_trans - i) == 1) // last loop or one and only loop
+		{
+			// last loop will contain a max of rel_wr_count number of frames or less
+			bytes_to_transfer = RPMB_FRAME_SIZE * blks_remaining;
+		}
+		else
+		{
+			bytes_to_transfer = RPMB_FRAME_SIZE * rel_wr_count;
+		}
+
 		// send the request
 		cdb_out_param = (struct scsi_sec_protocol_cdb*) cdb;
 		memset(cdb_out_param, 0, sizeof(struct scsi_sec_protocol_cdb));
@@ -190,6 +225,44 @@
 		cdb_out_param->opcode                = SCSI_CMD_SECPROT_OUT;
 		cdb_out_param->cdb1                  = SCSI_SEC_PROT;
 		cdb_out_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
+		cdb_out_param->alloc_tlen            = BE32(bytes_to_transfer);
+
+		// Flush CDB to memory
+		dsb();
+		arch_clean_invalidate_cache_range((addr_t) cdb_out_param, sizeof(struct scsi_sec_protocol_cdb));
+
+		memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
+
+		req_upiu.cdb              = (addr_t) cdb_out_param;
+		req_upiu.data_buffer_addr = (addr_t) req_buf;
+		req_upiu.data_len         = bytes_to_transfer;
+		req_upiu.flags            = UPIU_FLAGS_WRITE;
+		req_upiu.lun              = UFS_WLUN_RPMB;
+		req_upiu.dd               = UTRD_TARGET_TO_SYSTEM;
+
+#ifdef DEBUG_RPMB
+		dprintf(INFO, "Sending RPMB write request: Start\n");
+		for(uint8_t j = 0; j < (bytes_to_transfer/RPMB_FRAME_SIZE); j++)
+		{
+			dprintf(INFO, "request buffer address: %p\n", (req_buf + (j * RPMB_FRAME_SIZE)));
+			dump_rpmb_frame((uint8_t *)req_buf + (j * RPMB_FRAME_SIZE), "request");
+		}
+#endif
+		if (ucs_do_scsi_cmd(dev, &req_upiu))
+		{
+			dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
+			return -UFS_FAILURE;
+		}
+#ifdef DEBUG_RPMB
+		dprintf(INFO, "Sending RPMB write request: Done\n");
+#endif
+		// Result Read
+		cdb_out_param = (struct scsi_sec_protocol_cdb*) cdb;
+		memset(cdb_out_param, 0, sizeof(struct scsi_sec_protocol_cdb));
+
+		cdb_out_param->opcode                = SCSI_CMD_SECPROT_OUT;
+		cdb_out_param->cdb1                  = SCSI_SEC_PROT;
+		cdb_out_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
 		cdb_out_param->alloc_tlen            = BE32(RPMB_FRAME_SIZE);
 
 		// Flush CDB to memory
@@ -199,39 +272,6 @@
 		memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
 
 		req_upiu.cdb              = (addr_t) cdb_out_param;
-		req_upiu.data_buffer_addr = (addr_t) req_buf;
-		req_upiu.data_len         = RPMB_FRAME_SIZE;
-		req_upiu.flags            = UPIU_FLAGS_WRITE;
-		req_upiu.lun              = UFS_WLUN_RPMB;
-		req_upiu.dd               = UTRD_TARGET_TO_SYSTEM;
-
-#ifdef DEBUG_RPMB
-		dprintf(INFO, "Sending RPMB write request: Start\n");
-#endif
-		if (ucs_do_scsi_cmd(dev, &req_upiu))
-		{
-			dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
-			return -UFS_FAILURE;
-		}
-#ifdef DEBUG_RPMB
-		dprintf(INFO, "Sending RPMB write request: Done\n");
-#endif
-		// Result Read
-		cdb_in_param = (struct scsi_sec_protocol_cdb*) cdb;
-		memset(cdb_in_param, 0, sizeof(struct scsi_sec_protocol_cdb));
-
-		cdb_in_param->opcode                = SCSI_CMD_SECPROT_OUT;
-		cdb_in_param->cdb1                  = SCSI_SEC_PROT;
-		cdb_in_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
-		cdb_in_param->alloc_tlen            = BE32(RPMB_FRAME_SIZE);
-
-		// Flush CDB to memory
-		dsb();
-		arch_clean_invalidate_cache_range((addr_t) cdb_in_param, sizeof(struct scsi_sec_protocol_cdb));
-
-		memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
-
-		req_upiu.cdb              = (addr_t) cdb_in_param;
 		req_upiu.data_buffer_addr = (addr_t) &read_result_reg ;
 		req_upiu.data_len         = result_frame_bytes;
 		req_upiu.flags            = UPIU_FLAGS_WRITE;
@@ -247,7 +287,7 @@
 			return -UFS_FAILURE;
 		}
 #ifdef DEBUG_RPMB
-		dprintf(SPEW, "Sending RPMB Result Read Register: Done\n");
+		dprintf(INFO, "Sending RPMB Result Read Register: Done\n");
 #endif
 
 		// Retrieve verification result
@@ -280,12 +320,34 @@
 			dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
 			return -UFS_FAILURE;
 		}
+		// invalidate response buffer before reading response as this is part of request
+		// buffer overwritten
+		arch_clean_invalidate_cache_range((addr_t) resp_buf, result_frame_bytes);
 #ifdef DEBUG_RPMB
-		dprintf(SPEW, "Sending RPMB Response for Result Read Register: Done\n");
+		dprintf(INFO, "Sending RPMB Response for Result Read Register: Done\n");
 		dump_rpmb_frame((uint8_t *)resp_buf, "response");
 #endif
 
-		req_buf = (uint32_t*) ((uint8_t*)req_buf + RPMB_BLK_SIZE);
+		if (result->result[0] == 0x80)
+		{
+			dprintf(CRITICAL, "Max write counter reached: \n");
+			break;
+		}
+
+		if (result->result[1])
+		{
+			dprintf(CRITICAL, "UFS RPMB write error: %s\n", str_err[result->result[1]]);
+			break;
+		}
+		if ((num_trans - i) == 1)
+			continue; // last frame no need to increment
+		else
+		{
+			req_buf = (uint32_t*) ((uint8_t*)req_buf + (RPMB_BLK_SIZE * rel_wr_count));
+			// If more than 1 transaction, then until the last loop, we will be transfering
+			// rel_wr_count number of half sections in one transaction
+			blks_remaining = blks_remaining - rel_wr_count;
+		}
 	}
 
 	*resp_len = RPMB_MIN_BLK_CNT * RPMB_BLK_SIZE;
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index d19df24..d1ebd05 100644
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -508,6 +508,23 @@
 			$(LOCAL_DIR)/mipi_dsi_autopll.o
 endif
 
+ifeq ($(PLATFORM),mdmfermium)
+	OBJS += $(LOCAL_DIR)/qgic.o \
+			$(LOCAL_DIR)/qtimer.o \
+			$(LOCAL_DIR)/qtimer_mmap.o \
+			$(LOCAL_DIR)/interrupts.o \
+			$(LOCAL_DIR)/clock.o \
+			$(LOCAL_DIR)/clock_pll.o \
+			$(LOCAL_DIR)/clock_lib2.o \
+			$(LOCAL_DIR)/uart_dm.o \
+			$(LOCAL_DIR)/board.o \
+			$(LOCAL_DIR)/spmi.o \
+			$(LOCAL_DIR)/bam.o \
+			$(LOCAL_DIR)/qpic_nand.o \
+			$(LOCAL_DIR)/scm.o \
+			$(LOCAL_DIR)/dev_tree.o
+endif
+
 ifeq ($(PLATFORM),msm8996)
 DEFINES += DISPLAY_TYPE_MDSS=1
 	OBJS += $(LOCAL_DIR)/qtimer.o \
diff --git a/platform/msm_shared/sdhci.c b/platform/msm_shared/sdhci.c
index 72126bf..bfab9f1 100644
--- a/platform/msm_shared/sdhci.c
+++ b/platform/msm_shared/sdhci.c
@@ -863,7 +863,7 @@
 		/* Enable auto cmd23 or cmd12 for multi block transfer
 		 * based on what command card supports
 		 */
-		if (cmd->data.num_blocks > 1) {
+		if ((cmd->data.num_blocks > 1) && !cmd->rel_write) {
 			if (cmd->cmd23_support) {
 				trans_mode |= SDHCI_TRANS_MULTI | SDHCI_AUTO_CMD23_EN | SDHCI_BLK_CNT_EN;
 				REG_WRITE32(host, cmd->data.num_blocks, SDHCI_ARG2_REG);
@@ -871,6 +871,9 @@
 			else
 				trans_mode |= SDHCI_TRANS_MULTI | SDHCI_AUTO_CMD12_EN | SDHCI_BLK_CNT_EN;
 		}
+		else if ((cmd->data.num_blocks > 1) && cmd->rel_write) {
+			trans_mode |= SDHCI_TRANS_MULTI | SDHCI_BLK_CNT_EN;
+		}
 	}
 
 	/* Write to transfer mode register */
diff --git a/platform/msm_shared/smem.h b/platform/msm_shared/smem.h
index 5067b8a..aa8cd1f 100644
--- a/platform/msm_shared/smem.h
+++ b/platform/msm_shared/smem.h
@@ -428,6 +428,7 @@
 	APQ8076  = 277,
 	MSM8976  = 278,
 	APQ8052  = 289,
+	MDMFERMIUM  = 290,
 	APQ8096  = 291,
 };
 
diff --git a/project/mdmfermium.mk b/project/mdmfermium.mk
new file mode 100644
index 0000000..970594c
--- /dev/null
+++ b/project/mdmfermium.mk
@@ -0,0 +1,28 @@
+# top level project rules for the fermium project
+#
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+TARGET := mdmfermium
+
+MODULES += app/aboot
+
+ifeq ($(TARGET_BUILD_VARIANT),user)
+DEBUG := 0
+else
+DEBUG := 1
+endif
+
+DEFINES += WITH_DEBUG_UART=1
+DEFINES += DEVICE_TREE=1
+
+DEFINES += BAM_V170=1
+#Disable thumb mode
+ENABLE_THUMB := false
+
+#Override linker for mdm targets
+LD := $(TOOLCHAIN_PREFIX)ld.bfd
+
+ENABLE_SMD_SUPPORT := 1
+ifeq ($(ENABLE_SMD_SUPPORT),1)
+DEFINES += SMD_SUPPORT=1
+endif
diff --git a/project/msm8996.mk b/project/msm8996.mk
index eecf740..9dd510b 100644
--- a/project/msm8996.mk
+++ b/project/msm8996.mk
@@ -36,10 +36,10 @@
 
 DEFINES += ABOOT_IGNORE_BOOT_HEADER_ADDRS=1
 
-DEFINES += ABOOT_FORCE_KERNEL_ADDR=0x80008000
-DEFINES += ABOOT_FORCE_RAMDISK_ADDR=0x82200000
-DEFINES += ABOOT_FORCE_TAGS_ADDR=0x82000000
-DEFINES += ABOOT_FORCE_KERNEL64_ADDR=0x80080000
+DEFINES += ABOOT_FORCE_KERNEL_ADDR=0x20008000
+DEFINES += ABOOT_FORCE_RAMDISK_ADDR=0x22200000
+DEFINES += ABOOT_FORCE_TAGS_ADDR=0x22000000
+DEFINES += ABOOT_FORCE_KERNEL64_ADDR=0x20080000
 DEFINES += USB_RESET_FROM_CLK=1
 DEFINES += USE_BOOTDEV_CMDLINE=1
 DEFINES += USE_RPMB_FOR_DEVINFO=1
@@ -77,11 +77,6 @@
 DEFINES += MDTP_EFUSE_START=0
 endif
 
-ENABLE_WDOG_SUPPORT := 1
-ifeq ($(ENABLE_WDOG_SUPPORT),1)
-DEFINES += WDOG_SUPPORT=1
-endif
-
 ifeq ($(ENABLE_LPAE_SUPPORT),1)
 DEFINES += LPAE=1
 endif
diff --git a/target/mdm9640/init.c b/target/mdm9640/init.c
index 567ccde..2d2bb4b 100644
--- a/target/mdm9640/init.c
+++ b/target/mdm9640/init.c
@@ -84,7 +84,7 @@
 #define LAST_NAND_PTN_LEN_PATTERN                     0xFFFFFFFF
 
 #define EXT4_CMDLINE  " rootwait rootfstype=ext4 root=/dev/mmcblk0p"
-#define UBI_CMDLINE " rootfstype=ubifs rootflags=bulk_read ubi.fm_autoconvert=1"
+#define UBI_CMDLINE " rootfstype=ubifs rootflags=bulk_read"
 
 struct qpic_nand_init_config config;
 
@@ -135,6 +135,8 @@
 {
 	dprintf(INFO, "target_init()\n");
 
+	pmic_info_populate();
+
 	spmi_init(PMIC_ARB_CHANNEL_NUM, PMIC_ARB_OWNER_ID);
 
 	if (platform_boot_dev_isemmc()) {
diff --git a/target/mdmfermium/init.c b/target/mdmfermium/init.c
new file mode 100644
index 0000000..7e32f52
--- /dev/null
+++ b/target/mdmfermium/init.c
@@ -0,0 +1,279 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <platform/iomap.h>
+#include <reg.h>
+#include <target.h>
+#include <platform.h>
+#include <uart_dm.h>
+#include <platform/gpio.h>
+#include <lib/ptable.h>
+#include <qpic_nand.h>
+#include <dev/keys.h>
+#include <spmi_v2.h>
+#include <pm8x41.h>
+#include <board.h>
+#include <baseband.h>
+#include <hsusb.h>
+#include <scm.h>
+#include <platform/gpio.h>
+#include <platform/gpio.h>
+#include <platform/irqs.h>
+#include <platform/clock.h>
+#include <crypto5_wrapper.h>
+#include <partition_parser.h>
+#include <stdlib.h>
+
+#if LONG_PRESS_POWER_ON
+#include <shutdown_detect.h>
+#endif
+
+#define FASTBOOT_MODE           0x77665500
+#define PON_SOFT_RB_SPARE       0x88F
+
+extern void smem_ptable_init(void);
+extern void smem_add_modem_partitions(struct ptable *flash_ptable);
+
+static struct ptable flash_ptable;
+
+/* PMIC config data */
+#define PMIC_ARB_CHANNEL_NUM    0
+#define PMIC_ARB_OWNER_ID       0
+
+/* NANDc BAM pipe numbers */
+#define DATA_CONSUMER_PIPE      0
+#define DATA_PRODUCER_PIPE      1
+#define CMD_PIPE                2
+
+/* NANDc BAM pipe groups */
+#define DATA_PRODUCER_PIPE_GRP   0
+#define DATA_CONSUMER_PIPE_GRP   0
+#define CMD_PIPE_GRP             1
+
+/* NANDc EE */
+#define QPIC_NAND_EE      0
+
+/* NANDc max desc length. */
+#define QPIC_NAND_MAX_DESC_LEN   0x7FFF
+
+#define LAST_NAND_PTN_LEN_PATTERN 0xFFFFFFFF
+
+struct qpic_nand_init_config config;
+
+void update_ptable_names(void)
+{
+	uint32_t ptn_index;
+	struct ptentry *ptentry_ptr = flash_ptable.parts;
+	struct ptentry *boot_ptn;
+	unsigned i;
+	uint32_t len;
+
+	/* Change all names to lower case. */
+	for (ptn_index = 0; ptn_index != (uint32_t)flash_ptable.count; ptn_index++)
+	{
+		len = strlen(ptentry_ptr[ptn_index].name);
+		for (i = 0; i < len; i++)
+		{
+			if (isupper(ptentry_ptr[ptn_index].name[i]))
+			{
+				ptentry_ptr[ptn_index].name[i] = tolower(ptentry_ptr[ptn_index].name[i]);
+			}
+		}
+		/* SBL fills in the last partition length as 0xFFFFFFFF.
+	* Update the length field based on the number of blocks on the flash.*/
+		if ((uint32_t)(ptentry_ptr[ptn_index].length) == LAST_NAND_PTN_LEN_PATTERN)
+		{
+			ptentry_ptr[ptn_index].length = flash_num_blocks() - ptentry_ptr[ptn_index].start;
+		}
+	}
+}
+
+void target_early_init(void)
+{
+#if WITH_DEBUG_UART
+	uart_dm_init(1, 0, BLSP1_UART1_BASE);
+#endif
+}
+
+/* Configure PMIC and Drop PS_HOLD for shutdown */
+void shutdown_device()
+{
+	dprintf(CRITICAL, "Going down for shutdown.\n");
+
+	/* Configure PMIC for shutdown */
+	pm8x41_reset_configure(PON_PSHOLD_SHUTDOWN);
+
+	/* Drop PS_HOLD for MSM */
+	writel(0x00, MPM2_MPM_PS_HOLD);
+
+	mdelay(5000);
+
+	dprintf(CRITICAL, "shutdown failed\n");
+
+	ASSERT(0);
+}
+
+
+void target_init(void)
+{
+	uint32_t base_addr;
+	uint8_t slot;
+
+	dprintf(INFO, "target_init()\n");
+
+	spmi_init(PMIC_ARB_CHANNEL_NUM, PMIC_ARB_OWNER_ID);
+
+	config.pipes.read_pipe = DATA_PRODUCER_PIPE;
+	config.pipes.write_pipe = DATA_CONSUMER_PIPE;
+	config.pipes.cmd_pipe = CMD_PIPE;
+
+	config.pipes.read_pipe_grp = DATA_PRODUCER_PIPE_GRP;
+	config.pipes.write_pipe_grp = DATA_CONSUMER_PIPE_GRP;
+	config.pipes.cmd_pipe_grp = CMD_PIPE_GRP;
+
+	config.bam_base = MSM_NAND_BAM_BASE;
+	config.nand_base = MSM_NAND_BASE;
+	config.ee = QPIC_NAND_EE;
+	config.max_desc_len = QPIC_NAND_MAX_DESC_LEN;
+
+	qpic_nand_init(&config);
+
+	ptable_init(&flash_ptable);
+	//smem_ptable_init();
+	//smem_add_modem_partitions(&flash_ptable);
+
+	update_ptable_names();
+	flash_set_ptable(&flash_ptable);
+}
+
+/* Identify the current target */
+void target_detect(struct board_data *board)
+{
+	/* This property is filled as part of board.c */
+}
+
+unsigned board_machtype(void)
+{
+}
+
+/* Identify the baseband being used */
+void target_baseband_detect(struct board_data *board)
+{
+	uint32_t platform = board->platform;
+
+	switch(platform)
+	{
+	case MDMFERMIUM:
+		board->baseband = BASEBAND_MDM;
+        break;
+	default:
+		dprintf(CRITICAL, "Platform type: %u is not supported\n", platform);
+		ASSERT(0);
+	};
+}
+
+unsigned check_reboot_mode(void)
+{
+	uint32_t restart_reason = 0;
+
+	/* Read reboot reason and scrub it */
+	restart_reason = readl(RESTART_REASON_ADDR);
+	writel(0x00, RESTART_REASON_ADDR);
+
+	return restart_reason;
+}
+
+int get_target_boot_params(const char *cmdline, const char *part, char *buf,int buflen)
+{
+	struct ptable *ptable;
+	int system_ptn_index = -1;
+
+	ptable = flash_get_ptable();
+	if (!ptable) {
+		dprintf(CRITICAL,"WARN: Cannot get flash partition table\n");
+		return -1;
+	}
+
+	system_ptn_index = ptable_get_index(ptable, part);
+	if (system_ptn_index < 0) {
+		dprintf(CRITICAL,"WARN: Cannot get partition index for %s\n", part);
+		return -1;
+	}
+	/*check if cmdline contains "root=" at the beginning of buffer or
+	* " root=" in the middle of buffer.
+	*/
+	if (((!strncmp(cmdline, "root=", strlen("root="))) ||
+		(strstr(cmdline, " root="))))
+		dprintf(DEBUG, "DEBUG: cmdline has root=\n");
+	else
+		snprintf(buf, buflen, " root=/dev/mtdblock%d",system_ptn_index);
+	return 0;
+}
+
+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_uninit(void)
+{
+}
+
+void reboot_device(unsigned reboot_reason)
+{
+	 /* Write the reboot reason */
+	writel(reboot_reason, RESTART_REASON_ADDR);
+
+	/* Configure PMIC for warm reset */
+	/* PM 8019 v1 aligns with PM8941 v2.
+	* This call should be based on the pmic version
+	* when PM8019 v2 is available.
+	*/
+	pm8x41_v2_reset_configure(PON_PSHOLD_WARM_RESET);
+
+	/* Drop PS_HOLD for MSM */
+	writel(0x00, MPM2_MPM_PS_HOLD);
+
+	mdelay(5000);
+
+	dprintf(CRITICAL, "Rebooting failed\n");
+	return;
+}
diff --git a/target/mdmfermium/keypad.c b/target/mdmfermium/keypad.c
new file mode 100644
index 0000000..a57a2f8
--- /dev/null
+++ b/target/mdmfermium/keypad.c
@@ -0,0 +1,63 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ *  with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <reg.h>
+#include <platform/gpio.h>
+#include <platform/iomap.h>
+
+/* GPIO that controls the button
+ * for FASTBOOT.
+ */
+#define FASTBOOT_KEY_GPIO_ID        37
+
+/*
+ * Returns fastboot button state.
+ * Returns 0 if button is not pressed, 1 when pressed.
+ */
+int get_fastboot_key_state(void)
+{
+	int ret;
+
+	gpio_tlmm_config(FASTBOOT_KEY_GPIO_ID, 0, GPIO_INPUT, GPIO_PULL_DOWN, GPIO_2MA, GPIO_ENABLE);
+
+	ret = gpio_get_state(FASTBOOT_KEY_GPIO_ID);
+
+	return ret;
+}
+
+/*
+* Return 1 to trigger to fastboot
+*/
+int fastboot_trigger(void)
+{
+	int ret;
+
+	ret = get_fastboot_key_state();
+
+	return (ret);
+}
diff --git a/target/mdmfermium/meminfo.c b/target/mdmfermium/meminfo.c
new file mode 100644
index 0000000..b66166e
--- /dev/null
+++ b/target/mdmfermium/meminfo.c
@@ -0,0 +1,95 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <reg.h>
+#include <debug.h>
+#include <malloc.h>
+#include <smem.h>
+#include <stdint.h>
+#include <libfdt.h>
+#include <platform/iomap.h>
+#include <dev_tree.h>
+
+#define SIZE_1M             (1024 * 1024)
+static struct smem_ram_ptable ram_ptable;
+struct smem_ram_ptable* target_smem_ram_ptable_init()
+{
+	/* Make sure RAM partition table is initialized */
+	ASSERT(smem_ram_ptable_init(&ram_ptable));
+	return &ram_ptable;
+}
+
+uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset)
+{
+	ram_partition ptn_entry;
+	unsigned int index;
+	int ret = 0;
+	uint32_t len = 0;
+
+	/* Make sure RAM partition table is initialized */
+	ASSERT(smem_ram_ptable_init_v1());
+
+	len = smem_get_ram_ptable_len();
+
+	/* Calculating the size of the mem_info_ptr */
+	for (index = 0 ; index < len; index++)
+	{
+		smem_get_ram_ptable_entry(&ptn_entry, index);
+
+		if((ptn_entry.category == SDRAM) &&
+			(ptn_entry.type == SYS_MEMORY))
+		{
+
+			/* Pass along all other usable memory regions to Linux */
+			ret = dev_tree_add_mem_info(fdt,
+							memory_node_offset,
+							ptn_entry.start,
+							ptn_entry.size);
+
+			if (ret)
+			{
+				dprintf(CRITICAL, "Failed to add secondary banks memory addresses\n");
+				goto target_dev_tree_mem_err;
+			}
+		}
+	}
+target_dev_tree_mem_err:
+
+	return ret;
+}
+
+void *target_get_scratch_address(void)
+{
+	return ((void *)SCRATCH_ADDR);
+}
+
+unsigned target_get_max_flash_size(void)
+{
+	/*24.5MB*/
+	return (SCRATCH_REGION1_SIZE + SCRATCH_REGION2_SIZE);
+}
diff --git a/target/mdmfermium/rules.mk b/target/mdmfermium/rules.mk
new file mode 100644
index 0000000..ed3553f
--- /dev/null
+++ b/target/mdmfermium/rules.mk
@@ -0,0 +1,45 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+INCLUDES += -I$(LOCAL_DIR)/include -I$(LK_TOP_DIR)/platform/msm_shared
+
+PLATFORM := mdmfermium
+
+MEMBASE := 0x87A00000 # SDRAM
+MEMSIZE := 0x00100000 # 1MB
+
+SCRATCH_ADDR                        := 0x81200000
+SCRATCH_REGION1                     := 0x81200000
+SCRATCH_REGION1_SIZE                := 0x1800000  # 24MB
+SCRATCH_REGION2                     := 0x87F80000
+SCRATCH_REGION2_SIZE                := 0x80000    # 512KB
+
+KERNEL_REGION                       := 0x80000000
+KERNEL_REGION_SIZE                  := 0x1200000 # 18MB
+
+BASE_ADDR                           := 0x80000000
+
+DEFINES += NO_KEYPAD_DRIVER=1
+
+MODULES += \
+	dev/keys \
+	dev/vib \
+	lib/ptable \
+	dev/pmic/pm8x41 \
+	lib/libfdt
+
+DEFINES += \
+	MEMSIZE=$(MEMSIZE) \
+	MEMBASE=$(MEMBASE) \
+	BASE_ADDR=$(BASE_ADDR) \
+	SCRATCH_ADDR=$(SCRATCH_ADDR) \
+	SCRATCH_REGION1=$(SCRATCH_REGION1) \
+	SCRATCH_REGION2=$(SCRATCH_REGION2) \
+	SCRATCH_REGION1_SIZE=$(SCRATCH_REGION1_SIZE) \
+	SCRATCH_REGION2_SIZE=$(SCRATCH_REGION2_SIZE) \
+	KERNEL_REGION=$(KERNEL_REGION) \
+	KERNEL_REGION_SIZE=$(KERNEL_REGION_SIZE)
+
+OBJS += \
+	$(LOCAL_DIR)/init.o \
+	$(LOCAL_DIR)/meminfo.o \
+	$(LOCAL_DIR)/keypad.o
diff --git a/target/mdmfermium/tools/makefile b/target/mdmfermium/tools/makefile
new file mode 100644
index 0000000..8486761
--- /dev/null
+++ b/target/mdmfermium/tools/makefile
@@ -0,0 +1,14 @@
+#Makefile to generate appsboot.mbn
+
+ifeq ($(BOOTLOADER_OUT),.)
+APPSBOOTOUT_DIR  := $(BUILDDIR)
+else
+APPSBOOTOUT_DIR := $(BOOTLOADER_OUT)/../..
+endif
+
+ABOOTMBN := appsboot.mbn
+APPSBOOTHEADER: $(ABOOTMBN)
+
+$(ABOOTMBN): $(OUTELF_STRIP) $(OUTBIN)
+	cp $(OUTBIN) $(APPSBOOTOUT_DIR)/appsboot.raw
+	$(hide) cp -f $(OUTELF_STRIP) $(APPSBOOTOUT_DIR)/$(ABOOTMBN)
diff --git a/target/msm8952/include/target/display.h b/target/msm8952/include/target/display.h
index 5c02765..87cbc3a 100644
--- a/target/msm8952/include/target/display.h
+++ b/target/msm8952/include/target/display.h
@@ -91,8 +91,6 @@
 #define MIPI_VSYNC_BACK_PORCH_LINES  3
 #define MIPI_VSYNC_FRONT_PORCH_LINES 9
 
-#endif
-
 /*---------------------------------------------------------------------------*/
 /* Functions		                                                     */
 /*---------------------------------------------------------------------------*/
@@ -104,3 +102,6 @@
 int target_display_get_base_offset(uint32_t base);
 void target_force_cont_splash_disable(uint8_t override);
 uint8_t target_panel_auto_detect_enabled();
+uint32_t oem_panel_max_auto_detect_panels();
+
+#endif
diff --git a/target/msm8952/init.c b/target/msm8952/init.c
index 99550f5..e1a61c4 100644
--- a/target/msm8952/init.c
+++ b/target/msm8952/init.c
@@ -503,6 +503,23 @@
         splash_override = override;
 }
 
+uint8_t target_panel_auto_detect_enabled()
+{
+	uint8_t ret = 0;
+
+	switch(board_hardware_id())
+	{
+		case HW_PLATFORM_QRD:
+			ret = platform_is_msm8956() ? 1 : 0;
+			break;
+		case HW_PLATFORM_SURF:
+		case HW_PLATFORM_MTP:
+		default:
+			ret = 0;
+	}
+	return ret;
+}
+
 /* Do any target specific intialization needed before entering fastboot mode */
 void target_fastboot_init(void)
 {
diff --git a/target/msm8952/oem_panel.c b/target/msm8952/oem_panel.c
index b64ac32..603f990 100644
--- a/target/msm8952/oem_panel.c
+++ b/target/msm8952/oem_panel.c
@@ -49,6 +49,7 @@
 #include "include/panel_sharp_1080p_cmd.h"
 #include "include/panel_nt35597_wqxga_dualdsi_video.h"
 #include "include/panel_nt35597_wqxga_dualdsi_cmd.h"
+#include "include/panel_hx8399a_1080p_video.h"
 
 /*---------------------------------------------------------------------------*/
 /* static panel selection variable                                           */
@@ -60,6 +61,7 @@
 	SHARP_1080P_CMD_PANEL,
 	NT35597_WQXGA_DUALDSI_VIDEO_PANEL,
 	NT35597_WQXGA_DUALDSI_CMD_PANEL,
+	HX8399A_1080P_VIDEO_PANEL,
 	UNKNOWN_PANEL
 };
 
@@ -77,6 +79,8 @@
 	{"sharp_1080p_cmd", SHARP_1080P_CMD_PANEL},
 	{"nt35597_wqxga_dualdsi_video", NT35597_WQXGA_DUALDSI_VIDEO_PANEL},
 	{"nt35597_wqxga_dualdsi_cmd", NT35597_WQXGA_DUALDSI_CMD_PANEL},
+	{"otm1906c_1080p_cmd", OTM1906C_1080P_CMD_PANEL},
+	{"hx8399a_1080p_video", HX8399A_1080P_VIDEO_PANEL},
 };
 
 static uint32_t panel_id;
@@ -198,6 +202,31 @@
 			otm1906c_1080p_cmd_timings, TIMING_SIZE);
 		pinfo->mipi.signature = OTM1906C_1080P_CMD_SIGNATURE;
 		break;
+	case HX8399A_1080P_VIDEO_PANEL:
+		panelstruct->paneldata    = &hx8399a_1080p_video_panel_data;
+		panelstruct->panelres     = &hx8399a_1080p_video_panel_res;
+		panelstruct->color        = &hx8399a_1080p_video_color;
+		panelstruct->videopanel   = &hx8399a_1080p_video_video_panel;
+		panelstruct->commandpanel = &hx8399a_1080p_video_command_panel;
+		panelstruct->state        = &hx8399a_1080p_video_state;
+		panelstruct->laneconfig   = &hx8399a_1080p_video_lane_config;
+		panelstruct->paneltiminginfo
+			= &hx8399a_1080p_video_timing_info;
+		panelstruct->panelresetseq
+					 = &hx8399a_1080p_video_reset_seq;
+		panelstruct->backlightinfo = &hx8399a_1080p_video_backlight;
+		pinfo->mipi.panel_on_cmds
+			= hx8399a_1080p_video_on_command;
+		pinfo->mipi.num_of_panel_on_cmds
+			= HX8399A_1080P_VIDEO_ON_COMMAND;
+		pinfo->mipi.panel_off_cmds
+			= hx8399a_1080p_video_off_command;
+		pinfo->mipi.num_of_panel_off_cmds
+			= HX8399A_1080P_VIDEO_OFF_COMMAND;
+		memcpy(phy_db->timing,
+			hx8399a_1080p_video_timings, TIMING_SIZE);
+		pinfo->mipi.signature = HX8399A_1080P_VIDEO_SIGNATURE;
+		break;
 	case SHARP_1080P_CMD_PANEL:
 		panelstruct->paneldata    = &sharp_1080p_cmd_panel_data;
 		panelstruct->panelres     = &sharp_1080p_cmd_panel_res;
@@ -268,6 +297,9 @@
 		panelstruct->laneconfig   = &nt35597_wqxga_dualdsi_cmd_lane_config;
 		panelstruct->paneltiminginfo
 			= &nt35597_wqxga_dualdsi_cmd_timing_info;
+		/* Clkout timings are different for this panel on 8956 */
+		panelstruct->paneltiminginfo->tclk_post = 0x2b;
+		panelstruct->paneltiminginfo->tclk_pre = 0x28;
 		panelstruct->panelresetseq
 					 = &nt35597_wqxga_dualdsi_cmd_reset_seq;
 		panelstruct->backlightinfo = &nt35597_wqxga_dualdsi_cmd_backlight;
@@ -302,6 +334,15 @@
 	return pan_type;
 }
 
+#define DISPLAY_MAX_PANEL_DETECTION 2
+static uint32_t auto_pan_loop = 0;
+
+uint32_t oem_panel_max_auto_detect_panels()
+{
+	return target_panel_auto_detect_enabled() ?
+		DISPLAY_MAX_PANEL_DETECTION : 0;
+}
+
 int oem_panel_select(const char *panel_name, struct panel_struct *panelstruct,
 			struct msm_panel_info *pinfo,
 			struct mdss_dsi_phy_ctrl *phy_db)
@@ -341,6 +382,24 @@
 		break;
 	case HW_PLATFORM_QRD:
 		panel_id = OTM1906C_1080P_CMD_PANEL;
+
+		/* QRD EVT1 uses OTM1906C, and EVT2 uses HX8399A */
+		if (platform_is_msm8956()) {
+			switch (auto_pan_loop) {
+				case 0:
+					panel_id = HX8399A_1080P_VIDEO_PANEL;
+					break;
+				case 1:
+					panel_id = OTM1906C_1080P_CMD_PANEL;
+					break;
+				default:
+					panel_id = UNKNOWN_PANEL;
+					dprintf(CRITICAL, "Unknown panel\n");
+					return PANEL_TYPE_UNKNOWN;
+			}
+			auto_pan_loop++;
+		}
+
 		break;
 	default:
 		dprintf(CRITICAL, "Display not enabled for %d HW type\n",
diff --git a/target/msm8952/target_display.c b/target/msm8952/target_display.c
index e89beb5..adc5815 100644
--- a/target/msm8952/target_display.c
+++ b/target/msm8952/target_display.c
@@ -522,6 +522,8 @@
 void target_display_init(const char *panel_name)
 {
 	struct oem_panel_data oem;
+	int32_t ret = 0;
+	uint32_t panel_loop = 0;
 
 	set_panel_cmd_string(panel_name);
 	oem = mdss_dsi_get_oem_data();
@@ -535,10 +537,16 @@
 		return;
 	}
 
-	if (gcdb_display_init(oem.panel, MDP_REV_50, (void *)MIPI_FB_ADDR)) {
-		target_force_cont_splash_disable(true);
-		msm_display_off();
-	}
+	do {
+		target_force_cont_splash_disable(false);
+		ret = gcdb_display_init(oem.panel, MDP_REV_50, (void *)MIPI_FB_ADDR);
+		if (!ret || ret == ERR_NOT_SUPPORTED) {
+			break;
+		} else {
+			target_force_cont_splash_disable(true);
+			msm_display_off();
+		}
+	} while (++panel_loop <= oem_panel_max_auto_detect_panels());
 
 	if (!oem.cont_splash) {
 		dprintf(INFO, "Forcing continuous splash disable\n");
diff --git a/target/msm8996/rules.mk b/target/msm8996/rules.mk
index 57e3c4a..8966c0a 100644
--- a/target/msm8996/rules.mk
+++ b/target/msm8996/rules.mk
@@ -12,12 +12,11 @@
 
 SCRATCH_ADDR := 0x91100000
 SCRATCH_SIZE := 750
-KERNEL_ADDR  := 0x80000000
-KERNEL_SIZE  := 88
+KERNEL_ADDR  := 0x20000000
+KERNEL_SIZE  := 512
 # LPAE supports only 32 virtual address, L1 pt size is 4
 L1_PT_SZ     := 4
-L2_PT_SZ     := 2
-
+L2_PT_SZ     := 3
 
 DEFINES += DISPLAY_SPLASH_SCREEN=1
 DEFINES += DISPLAY_TYPE_MIPI=1