Merge "init: Add generic set_download_mode() function"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 6840c43..1ebc41e 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -90,6 +90,8 @@
 
 static const char *emmc_cmdline = " androidboot.emmc=true";
 static const char *usb_sn_cmdline = " androidboot.serialno=";
+static const char *androidboot_mode = " androidboot.mode=";
+static const char *loglevel         = " quiet";
 static const char *battchg_pause = " androidboot.mode=charger";
 static const char *auth_kernel = " androidboot.authorized_kernel=true";
 
@@ -185,6 +187,8 @@
 	int have_cmdline = 0;
 	unsigned char *cmdline_final = NULL;
 	int pause_at_bootup = 0;
+	char ffbm[10];
+	bool boot_into_ffbm = get_ffbm(ffbm, sizeof(ffbm));
 
 	if (cmdline && cmdline[0]) {
 		cmdline_len = strlen(cmdline);
@@ -197,7 +201,12 @@
 	cmdline_len += strlen(usb_sn_cmdline);
 	cmdline_len += strlen(sn_buf);
 
-	if (target_pause_for_battery_charge()) {
+	if (boot_into_ffbm) {
+		cmdline_len += strlen(androidboot_mode);
+		cmdline_len += strlen(ffbm);
+		/* reduce kernel console messages to speed-up boot */
+		cmdline_len += strlen(loglevel);
+	} else if (target_pause_for_battery_charge()) {
 		pause_at_bootup = 1;
 		cmdline_len += strlen(battchg_pause);
 	}
@@ -273,7 +282,17 @@
 		have_cmdline = 1;
 		while ((*dst++ = *src++));
 
-		if (pause_at_bootup) {
+		if (boot_into_ffbm) {
+			src = androidboot_mode;
+			if (have_cmdline) --dst;
+			while ((*dst++ = *src++));
+			src = ffbm;
+			if (have_cmdline) --dst;
+			while ((*dst++ = *src++));
+			src = loglevel;
+			if (have_cmdline) --dst;
+			while ((*dst++ = *src++));
+		} else if (pause_at_bootup) {
 			src = battchg_pause;
 			if (have_cmdline) --dst;
 			while ((*dst++ = *src++));
diff --git a/app/aboot/recovery.c b/app/aboot/recovery.c
index 566d245..c96490f 100644
--- a/app/aboot/recovery.c
+++ b/app/aboot/recovery.c
@@ -37,6 +37,7 @@
 #include <lib/ptable.h>
 #include <dev/keys.h>
 #include <platform.h>
+#include <target.h>
 #include <partition_parser.h>
 #include <mmc.h>
 
@@ -51,6 +52,7 @@
 static const int MISC_PAGES = 3;			// number of pages to save
 static const int MISC_COMMAND_PAGE = 1;		// bootloader command is this page
 static char buf[4096];
+
 unsigned boot_into_recovery = 0;
 
 extern void reset_device_info();
@@ -295,10 +297,11 @@
 	// get recovery message
 	if (get_recovery_message(&msg))
 		return -1;
-	if (msg.command[0] != 0 && msg.command[0] != 255) {
-		dprintf(INFO, "Recovery command: %.*s\n", sizeof(msg.command), msg.command);
-	}
 	msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
+	if (msg.command[0] != 0 && msg.command[0] != 255) {
+		dprintf(INFO,"Recovery command: %d %s\n",
+			sizeof(msg.command), msg.command);
+	}
 
 	if (!strcmp("boot-recovery",msg.command))
 	{
@@ -429,10 +432,11 @@
 	// get recovery message
 	if(emmc_get_recovery_msg(&msg))
 		return -1;
-	if (msg.command[0] != 0 && msg.command[0] != 255) {
-		dprintf(INFO,"Recovery command: %d %s\n", sizeof(msg.command), msg.command);
-	}
 	msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
+	if (msg.command[0] != 0 && msg.command[0] != 255) {
+		dprintf(INFO,"Recovery command: %d %s\n",
+			sizeof(msg.command), msg.command);
+	}
 
 	if (!strncmp(msg.command, "boot-recovery", strlen("boot-recovery"))) {
 		boot_into_recovery = 1;
@@ -470,3 +474,193 @@
 	emmc_set_recovery_msg(&msg);	// send recovery message
 	return 0;
 }
+
+static int read_misc(unsigned page_offset, void *buf, unsigned size)
+{
+	const char *ptn_name = "misc";
+	void *scratch_addr = target_get_scratch_address();
+	unsigned offset;
+	unsigned aligned_size;
+
+	if (size == 0 || buf == NULL || scratch_addr == NULL)
+		return -1;
+
+	if (target_is_emmc_boot())
+	{
+		int index;
+		unsigned long long ptn;
+		unsigned long long ptn_size;
+
+		index = partition_get_index(ptn_name);
+		if (index == INVALID_PTN)
+		{
+			dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
+			return -1;
+		}
+
+		ptn = partition_get_offset(index);
+		ptn_size = partition_get_size(index);
+
+		offset = page_offset * BLOCK_SIZE;
+		aligned_size = ROUND_TO_PAGE(size, (unsigned)BLOCK_SIZE - 1);
+		if (ptn_size < offset + aligned_size)
+		{
+			dprintf(CRITICAL, "Read request out of '%s' boundaries\n",
+					ptn_name);
+			return -1;
+		}
+
+		if (mmc_read(ptn + offset, (unsigned int *)scratch_addr, aligned_size))
+		{
+			dprintf(CRITICAL, "Reading MMC failed\n");
+			return -1;
+		}
+	}
+	else
+	{
+		struct ptentry *ptn;
+		struct ptable *ptable;
+		unsigned pagesize = flash_page_size();
+
+		ptable = flash_get_ptable();
+		if (ptable == NULL)
+		{
+			dprintf(CRITICAL, "Partition table not found\n");
+			return -1;
+		}
+
+		ptn = ptable_find(ptable, ptn_name);
+		if (ptn == NULL)
+		{
+			dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
+			return -1;
+		}
+
+		offset = page_offset * pagesize;
+		aligned_size = ROUND_TO_PAGE(size, pagesize - 1);
+		if (ptn->length < offset + aligned_size)
+		{
+			dprintf(CRITICAL, "Read request out of '%s' boundaries\n",
+					ptn_name);
+			return -1;
+		}
+
+		if (flash_read(ptn, offset, scratch_addr, aligned_size)) {
+			dprintf(CRITICAL, "Reading flash failed\n");
+			return -1;
+		}
+	}
+
+	if (scratch_addr != buf)
+		memcpy(buf, scratch_addr, size);
+
+	return 0;
+}
+
+int write_misc(unsigned page_offset, void *buf, unsigned size)
+{
+	const char *ptn_name = "misc";
+	void *scratch_addr = target_get_scratch_address();
+	unsigned offset;
+	unsigned aligned_size;
+
+	if (size == 0 || buf == NULL || scratch_addr == NULL)
+		return -1;
+
+	if (target_is_emmc_boot())
+	{
+		int index;
+		unsigned long long ptn;
+		unsigned long long ptn_size;
+
+		index = partition_get_index(ptn_name);
+		if (index == INVALID_PTN)
+		{
+			dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
+			return -1;
+		}
+
+		ptn = partition_get_offset(index);
+		ptn_size = partition_get_size(index);
+
+		offset = page_offset * BLOCK_SIZE;
+		aligned_size = ROUND_TO_PAGE(size, (unsigned)BLOCK_SIZE - 1);
+		if (ptn_size < offset + aligned_size)
+		{
+			dprintf(CRITICAL, "Write request out of '%s' boundaries\n",
+					ptn_name);
+			return -1;
+		}
+
+		if (scratch_addr != buf)
+			memcpy(scratch_addr, buf, size);
+		if (mmc_write(ptn + offset, aligned_size, (unsigned int *)scratch_addr))
+		{
+			dprintf(CRITICAL, "Writing MMC failed\n");
+			return -1;
+		}
+	}
+	else
+	{
+		struct ptentry *ptn;
+		struct ptable *ptable;
+		unsigned pagesize = flash_page_size();
+
+		ptable = flash_get_ptable();
+		if (ptable == NULL)
+		{
+			dprintf(CRITICAL, "Partition table not found\n");
+			return -1;
+		}
+
+		ptn = ptable_find(ptable, ptn_name);
+		if (ptn == NULL)
+		{
+			dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
+			return -1;
+		}
+
+		offset = page_offset * pagesize;
+		aligned_size = ROUND_TO_PAGE(size, pagesize - 1);
+		if (ptn->length < offset + aligned_size)
+		{
+			dprintf(CRITICAL, "Write request out of '%s' boundaries\n",
+					ptn_name);
+			return -1;
+		}
+
+		if (scratch_addr != buf)
+			memcpy(scratch_addr, buf, size);
+		if (flash_write(ptn, offset, scratch_addr, aligned_size)) {
+			dprintf(CRITICAL, "Writing flash failed\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+bool get_ffbm(char *ffbm, unsigned size)
+{
+	const char *ffbm_cmd = "ffbm-";
+	const unsigned ffbm_submode_size = 2;
+	unsigned ffbm_mode_size = strlen(ffbm_cmd) + ffbm_submode_size;
+
+	if (size < ffbm_mode_size + 1)
+	{
+		dprintf(CRITICAL, "Buffer too short to get FFBM string\n");
+		return false;
+	}
+
+	if (read_misc(0, ffbm, ffbm_mode_size))
+	{
+		dprintf(CRITICAL, "Error reading MISC partition\n");
+		return false;
+	}
+	ffbm[ffbm_mode_size] = 0;
+
+	if (!strncmp(ffbm, ffbm_cmd, strlen(ffbm_cmd)))
+		return true;
+
+	return false;
+}
diff --git a/app/aboot/recovery.h b/app/aboot/recovery.h
index 6037213..0d6289a 100644
--- a/app/aboot/recovery.h
+++ b/app/aboot/recovery.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, 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
@@ -62,7 +62,7 @@
 	unsigned fail_bitmap_length;
 };
 
-
+int write_misc(unsigned page_offset, void *buf, unsigned size);
 
 int get_recovery_message(struct recovery_message *out);
 int set_recovery_message(const struct recovery_message *in);
@@ -72,6 +72,8 @@
 
 int recovery_init (void);
 
+bool get_ffbm(char *ffbm, unsigned size);
+
 extern unsigned boot_into_recovery;
 
 #endif
diff --git a/include/target.h b/include/target.h
index b9dde60..6c4486d 100644
--- a/include/target.h
+++ b/include/target.h
@@ -1,6 +1,8 @@
 /*
  * Copyright (c) 2008 Travis Geiselbrecht
  *
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files
  * (the "Software"), to deal in the Software without restriction,
@@ -46,6 +48,7 @@
 unsigned target_baseband(void);
 void target_serialno(unsigned char *buf);
 void target_fastboot_init(void);
+struct mmc_device *target_mmc_device();
 
 
 #endif
diff --git a/platform/msm8226/acpuclock.c b/platform/msm8226/acpuclock.c
index 96e8687..a9e14e3 100644
--- a/platform/msm8226/acpuclock.c
+++ b/platform/msm8226/acpuclock.c
@@ -118,9 +118,6 @@
 
 	snprintf(clk_name, 64, "sdc%u_core_clk", interface);
 
-	/* Disalbe MCI_CLK before changing the sdcc clock */
-	mmc_boot_mci_clk_disable();
-
 	if(freq == MMC_CLK_400KHZ)
 	{
 		ret = clk_get_set_enable(clk_name, 400000, 1);
@@ -129,6 +126,10 @@
 	{
 		ret = clk_get_set_enable(clk_name, 50000000, 1);
 	}
+	else if(freq == MMC_CLK_200MHZ)
+	{
+		ret = clk_get_set_enable(clk_name, 200000000, 1);
+	}
 	else
 	{
 		dprintf(CRITICAL, "sdc frequency (%d) is not supported\n", freq);
@@ -141,9 +142,6 @@
 		dprintf(CRITICAL, "failed to set sdc1_core_clk ret = %d\n", ret);
 		ASSERT(0);
 	}
-
-	/* Enable MCI CLK */
-	mmc_boot_mci_clk_enable();
 }
 
 /* Configure UART clock based on the UART block id*/
diff --git a/platform/msm8226/include/platform/gpio.h b/platform/msm8226/include/platform/gpio.h
index ac554da..02849ab 100644
--- a/platform/msm8226/include/platform/gpio.h
+++ b/platform/msm8226/include/platform/gpio.h
@@ -30,6 +30,7 @@
 #define __PLATFORM_MSM8226_GPIO_H
 
 #include <bits.h>
+#include <gpio.h>
 
 /* GPIO TLMM: Direction */
 #define GPIO_INPUT      0
diff --git a/platform/msm8226/include/platform/iomap.h b/platform/msm8226/include/platform/iomap.h
index d459984..83f22b7 100644
--- a/platform/msm8226/include/platform/iomap.h
+++ b/platform/msm8226/include/platform/iomap.h
@@ -51,13 +51,16 @@
 
 #define MSM_SDC1_BAM_BASE           (PERIPH_SS_BASE + 0x00004000)
 #define MSM_SDC1_BASE               (PERIPH_SS_BASE + 0x00024000)
+#define MSM_SDC1_SDHCI_BASE         (PERIPH_SS_BASE + 0x00024900)
 #define MSM_SDC1_DML_BASE           (PERIPH_SS_BASE + 0x00024800)
 #define MSM_SDC3_BAM_BASE           (PERIPH_SS_BASE + 0x00044000)
 #define MSM_SDC3_BASE               (PERIPH_SS_BASE + 0x00064000)
+#define MSM_SDC3_SDHCI_BASE         (PERIPH_SS_BASE + 0x00064900)
 #define MSM_SDC3_DML_BASE           (PERIPH_SS_BASE + 0x00064800)
 #define MSM_SDC2_BAM_BASE           (PERIPH_SS_BASE + 0x00084000)
 #define MSM_SDC2_BASE               (PERIPH_SS_BASE + 0x000A4000)
 #define MSM_SDC2_DML_BASE           (PERIPH_SS_BASE + 0x000A4800)
+#define MSM_SDC2_SDHCI_BASE         (PERIPH_SS_BASE + 0x000A4900)
 
 #define BLSP1_UART0_BASE            (PERIPH_SS_BASE + 0x0011D000)
 #define BLSP1_UART1_BASE            (PERIPH_SS_BASE + 0x0011E000)
@@ -127,4 +130,11 @@
 #define USB_HS_SYSTEM_CMD_RCGR      (CLK_CTL_BASE + 0x490)
 #define USB_HS_SYSTEM_CFG_RCGR      (CLK_CTL_BASE + 0x494)
 
+/* SDHCI */
+#define SDCC_MCI_HC_MODE            (PERIPH_SS_BASE + 0x00024078)
+#define SDCC_HC_PWRCTL_MASK_REG     (PERIPH_SS_BASE + 0x000240E0)
+#define SDCC_HC_PWRCTL_CTL_REG      (PERIPH_SS_BASE + 0x000240E8)
+
+/* DRV strength for sdcc */
+#define SDC1_HDRV_PULL_CTL           (TLMM_BASE_ADDR + 0x00002044)
 #endif
diff --git a/platform/msm8226/include/platform/irqs.h b/platform/msm8226/include/platform/irqs.h
index c490a0b..2e29d3a 100644
--- a/platform/msm8226/include/platform/irqs.h
+++ b/platform/msm8226/include/platform/irqs.h
@@ -47,6 +47,8 @@
 #define USB1_HS_BAM_IRQ                        (GIC_SPI_START + 135)
 #define USB1_HS_IRQ                            (GIC_SPI_START + 134)
 
+#define SDCC_PWRCTRL_IRQ                       (GIC_SPI_START + 138)
+
 /* Retrofit universal macro names */
 #define INT_USB_HS                             USB1_HS_IRQ
 
diff --git a/platform/msm8974/gpio.c b/platform/msm8974/gpio.c
index d36cd6d..13097da 100644
--- a/platform/msm8974/gpio.c
+++ b/platform/msm8974/gpio.c
@@ -89,32 +89,3 @@
 		};
 	}
 }
-
-static void tlmm_set_sdc_pins(struct tlmm_cfgs *cfg)
-{
-	uint32_t reg_val;
-
-	reg_val = readl(SDC1_HDRV_PULL_CTL);
-
-	reg_val &= ~(cfg->mask << cfg->off);
-
-	reg_val |= (cfg->val << cfg->off);
-
-	writel(reg_val, SDC1_HDRV_PULL_CTL);
-}
-
-void tlmm_set_hdrive_ctrl(struct tlmm_cfgs *hdrv_cfgs, uint8_t sz)
-{
-	uint8_t i;
-
-	for (i = 0; i < sz; i++)
-		tlmm_set_sdc_pins(&hdrv_cfgs[i]);
-}
-
-void tlmm_set_pull_ctrl(struct tlmm_cfgs *pull_cfgs, uint8_t sz)
-{
-	uint8_t i;
-
-	for (i = 0; i < sz; i++)
-		tlmm_set_sdc_pins(&pull_cfgs[i]);
-}
diff --git a/platform/msm8974/include/platform/gpio.h b/platform/msm8974/include/platform/gpio.h
index 8c4bba8..8dc68f2 100644
--- a/platform/msm8974/include/platform/gpio.h
+++ b/platform/msm8974/include/platform/gpio.h
@@ -29,6 +29,8 @@
 #ifndef __PLATFORM_COPPER_GPIO_H
 #define __PLATFORM_COPPER_GPIO_H
 
+#include <gpio.h>
+
 /* GPIO TLMM: Direction */
 #define GPIO_INPUT      0
 #define GPIO_OUTPUT     1
@@ -53,36 +55,6 @@
 #define GPIO_ENABLE     0
 #define GPIO_DISABLE    1
 
-#define TLMM_PULL_MASK  0x3
-#define TLMM_HDRV_MASK  0x7
-
-enum {
-	TLMM_CUR_VAL_16MA = 0x7,
-	TLMM_CUR_VAL_10MA = 0x4,
-} tlmm_drive_config;
-
-enum {
-	TLMM_PULL_UP = 0x3,
-	TLMM_NO_PULL = 0x0,
-} tlmm_pull_values;
-
-enum {
-	SDC1_DATA_HDRV_CTL_OFF = 0,
-	SDC1_CMD_HDRV_CTL_OFF  = 3,
-	SDC1_CLK_HDRV_CTL_OFF  = 6,
-	SDC1_DATA_PULL_CTL_OFF = 9,
-	SDC1_CMD_PULL_CTL_OFF  = 11,
-	SDC1_CLK_PULL_CTL_OFF  = 13,
-} tlmm_drv_ctrl;
-
-struct tlmm_cfgs {
-	uint32_t off;
-	uint8_t val;
-	uint8_t mask;
-};
-
 void gpio_config_uart_dm(uint8_t id);
 void gpio_config_blsp_i2c(uint8_t, uint8_t);
-void tlmm_set_hdrive_ctrl(struct tlmm_cfgs *, uint8_t);
-void tlmm_set_pull_ctrl(struct tlmm_cfgs *, uint8_t);
 #endif
diff --git a/platform/msm_shared/gpio.c b/platform/msm_shared/gpio.c
new file mode 100644
index 0000000..137f00a
--- /dev/null
+++ b/platform/msm_shared/gpio.c
@@ -0,0 +1,62 @@
+/* Copyright (c) 2013, 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 <bits.h>
+#include <platform/iomap.h>
+#include <gpio.h>
+
+static void tlmm_set_sdc_pins(struct tlmm_cfgs *cfg)
+{
+	uint32_t reg_val;
+
+	reg_val = readl(SDC1_HDRV_PULL_CTL);
+
+	reg_val &= ~(cfg->mask << cfg->off);
+
+	reg_val |= (cfg->val << cfg->off);
+
+	writel(reg_val, SDC1_HDRV_PULL_CTL);
+}
+
+void tlmm_set_hdrive_ctrl(struct tlmm_cfgs *hdrv_cfgs, uint8_t sz)
+{
+	uint8_t i;
+
+	for (i = 0; i < sz; i++)
+		tlmm_set_sdc_pins(&hdrv_cfgs[i]);
+}
+
+void tlmm_set_pull_ctrl(struct tlmm_cfgs *pull_cfgs, uint8_t sz)
+{
+	uint8_t i;
+
+	for (i = 0; i < sz; i++)
+		tlmm_set_sdc_pins(&pull_cfgs[i]);
+}
diff --git a/platform/msm_shared/include/gpio.h b/platform/msm_shared/include/gpio.h
new file mode 100644
index 0000000..2a95eda
--- /dev/null
+++ b/platform/msm_shared/include/gpio.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2013, 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, Inc. 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 _GPIO_H_
+#define _GPIO_H_
+
+#define TLMM_PULL_MASK  0x3
+#define TLMM_HDRV_MASK  0x7
+
+/* Current values for tlmm pins */
+enum {
+	TLMM_CUR_VAL_16MA = 0x7,
+	TLMM_CUR_VAL_10MA = 0x4,
+} tlmm_drive_config;
+
+enum {
+	TLMM_PULL_UP = 0x3,
+	TLMM_NO_PULL = 0x0,
+} tlmm_pull_values;
+
+/* Bit offsets in the TLMM register */
+enum {
+	SDC1_DATA_HDRV_CTL_OFF = 0,
+	SDC1_CMD_HDRV_CTL_OFF  = 3,
+	SDC1_CLK_HDRV_CTL_OFF  = 6,
+	SDC1_DATA_PULL_CTL_OFF = 9,
+	SDC1_CMD_PULL_CTL_OFF  = 11,
+	SDC1_CLK_PULL_CTL_OFF  = 13,
+} tlmm_drv_ctrl;
+
+/* Input for the tlmm config function */
+struct tlmm_cfgs {
+	uint32_t off;  /* Bit offeset in the register */
+	uint8_t val;   /* Current value */
+	uint8_t mask;  /* Mask for the clk/dat/cmd control */
+};
+
+/* APIs: exposed for other drivers */
+/* API: Hdrive control for tlmm pins */
+void tlmm_set_hdrive_ctrl(struct tlmm_cfgs *, uint8_t);
+/* API:  Pull control for tlmm pins */
+void tlmm_set_pull_ctrl(struct tlmm_cfgs *, uint8_t);
+#endif
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index 46f7cb3..107960d 100644
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -93,7 +93,8 @@
 			$(LOCAL_DIR)/crypto_hash.o \
 			$(LOCAL_DIR)/crypto5_eng.o \
 			$(LOCAL_DIR)/crypto5_wrapper.o \
-			$(LOCAL_DIR)/i2c_qup.o
+			$(LOCAL_DIR)/i2c_qup.o \
+			$(LOCAL_DIR)/gpio.o
 endif
 
 ifeq ($(PLATFORM),msm8226)
@@ -114,7 +115,8 @@
             $(LOCAL_DIR)/crypto_hash.o \
             $(LOCAL_DIR)/crypto5_eng.o \
             $(LOCAL_DIR)/crypto5_wrapper.o \
-			$(LOCAL_DIR)/dev_tree.o
+			$(LOCAL_DIR)/dev_tree.o \
+			$(LOCAL_DIR)/gpio.o
 endif
 
 ifeq ($(PLATFORM),msm8610)
diff --git a/project/msm8226.mk b/project/msm8226.mk
index a9d45b2..262abc8 100644
--- a/project/msm8226.mk
+++ b/project/msm8226.mk
@@ -7,6 +7,7 @@
 MODULES += app/aboot
 
 DEBUG := 1
+ENABLE_SDHCI_SUPPORT := 1
 
 #DEFINES += WITH_DEBUG_DCC=1
 DEFINES += WITH_DEBUG_UART=1
@@ -14,3 +15,7 @@
 DEFINES += DEVICE_TREE=1
 #DEFINES += MMC_BOOT_BAM=1
 DEFINES += CRYPTO_BAM=1
+
+ifeq ($(ENABLE_SDHCI_SUPPORT),1)
+DEFINES += MMC_SDHCI_SUPPORT=1
+endif
diff --git a/target/init.c b/target/init.c
index 764901a..937f136 100644
--- a/target/init.c
+++ b/target/init.c
@@ -24,7 +24,6 @@
 #include <debug.h>
 #include <target.h>
 #include <compiler.h>
-#include <mmc.h>
 
 #define EXPAND(NAME) #NAME
 #define TARGET(NAME) EXPAND(NAME)
@@ -123,14 +122,3 @@
 __WEAK void target_usb_stop(void)
 {
 }
-
-/*
- * Default target specific function to set the capabilities for the host
- */
-__WEAK void target_mmc_caps(struct mmc_host *host)
-{
-	host->caps.ddr_mode = 0;
-	host->caps.hs200_mode = 0;
-	host->caps.bus_width = MMC_BOOT_BUS_WIDTH_4_BIT;
-	host->caps.hs_clk_rate = MMC_CLK_50MHZ;
-}
diff --git a/target/msm8226/init.c b/target/msm8226/init.c
index e07c4b1..e037090 100644
--- a/target/msm8226/init.c
+++ b/target/msm8226/init.c
@@ -32,7 +32,7 @@
 #include <target.h>
 #include <platform.h>
 #include <uart_dm.h>
-#include <mmc.h>
+#include <mmc_sdhci.h>
 #include <platform/gpio.h>
 #include <spmi.h>
 #include <board.h>
@@ -44,6 +44,7 @@
 #include <hsusb.h>
 
 extern  bool target_use_signed_kernel(void);
+static void set_sdc_power_ctrl(void);
 
 #define PMIC_ARB_CHANNEL_NUM               0
 #define PMIC_ARB_OWNER_ID                  0
@@ -57,8 +58,10 @@
 
 #define TLMM_VOL_UP_BTN_GPIO    106
 
-static uint32_t mmc_sdc_base[] =
-	{ MSM_SDC1_BASE, MSM_SDC2_BASE, MSM_SDC3_BASE };
+static uint32_t mmc_sdhci_base[] =
+	{ MSM_SDC1_SDHCI_BASE, MSM_SDC2_SDHCI_BASE, MSM_SDC3_SDHCI_BASE };
+
+struct mmc_device *dev;
 
 void target_early_init(void)
 {
@@ -124,31 +127,53 @@
 	crypto_init_params(&ce_params);
 }
 
+void target_sdc_init()
+{
+	struct mmc_config_data config;
+
+	/*
+	 * Set drive strength & pull ctrl for emmc
+	 */
+	set_sdc_power_ctrl();
+
+	/* Enable sdhci mode */
+	sdhci_mode_enable(1);
+
+	config.bus_width = DATA_BUS_WIDTH_8BIT;
+	config.max_clk_rate = MMC_CLK_200MHZ;
+
+	/* Trying Slot 1*/
+	config.slot = 1;
+	config.base = mmc_sdhci_base[config.slot - 1];
+	if (!(dev = mmc_init(&config)))
+	{
+		/* Trying Slot 2 next */
+		config.slot = 2;
+		config.base = mmc_sdhci_base[config.slot - 1];
+		if (!(dev = mmc_init(&config))) {
+			dprintf(CRITICAL, "mmc init failed!");
+			ASSERT(0);
+		}
+	}
+
+	/*
+	 * MMC initialization is complete, read the partition table info
+	 */
+	if (partition_read_table()) {
+		dprintf(CRITICAL, "Error reading the partition table info\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);
 
 	target_keystatus();
 
-	/* Trying Slot 1*/
-	slot = 1;
-	base_addr = mmc_sdc_base[slot - 1];
-	if (mmc_boot_main(slot, base_addr))
-	{
-
-		/* Trying Slot 2 next */
-		slot = 2;
-		base_addr = mmc_sdc_base[slot - 1];
-		if (mmc_boot_main(slot, base_addr)) {
-			dprintf(CRITICAL, "mmc init failed!");
-			ASSERT(0);
-		}
-	}
+	target_sdc_init();
 
 	if (target_use_signed_kernel())
 		target_crypto_init_params();
@@ -295,3 +320,31 @@
 {
        return _emmc_recovery_init();
 }
+
+static void set_sdc_power_ctrl()
+{
+	/* Drive strength configs for sdc pins */
+	struct tlmm_cfgs sdc1_hdrv_cfg[] =
+	{
+		{ SDC1_CLK_HDRV_CTL_OFF,  TLMM_CUR_VAL_10MA, TLMM_HDRV_MASK },
+		{ SDC1_CMD_HDRV_CTL_OFF,  TLMM_CUR_VAL_10MA, TLMM_HDRV_MASK },
+		{ SDC1_DATA_HDRV_CTL_OFF, TLMM_CUR_VAL_10MA, TLMM_HDRV_MASK },
+	};
+
+	/* Pull configs for sdc pins */
+	struct tlmm_cfgs sdc1_pull_cfg[] =
+	{
+		{ SDC1_CLK_PULL_CTL_OFF,  TLMM_NO_PULL, TLMM_PULL_MASK },
+		{ SDC1_CMD_PULL_CTL_OFF,  TLMM_PULL_UP, TLMM_PULL_MASK },
+		{ SDC1_DATA_PULL_CTL_OFF, TLMM_PULL_UP, TLMM_PULL_MASK },
+	};
+
+	/* Set the drive strength & pull control values */
+	tlmm_set_hdrive_ctrl(sdc1_hdrv_cfg, ARRAY_SIZE(sdc1_hdrv_cfg));
+	tlmm_set_pull_ctrl(sdc1_pull_cfg, ARRAY_SIZE(sdc1_pull_cfg));
+}
+
+struct mmc_device *target_mmc_device()
+{
+	return dev;
+}