Merge "ipq807x: Removed spi gpio entries from device-tree"
diff --git a/arch/arm/dts/ipq5018-emulation.dts b/arch/arm/dts/ipq5018-emulation.dts
index f3a6a5c..d0b1b05 100644
--- a/arch/arm/dts/ipq5018-emulation.dts
+++ b/arch/arm/dts/ipq5018-emulation.dts
@@ -17,9 +17,15 @@
 	model ="QCA, IPQ5018-EMULATION";
 	compatible = "qca,ipq5018", "qca,ipq5018-emulation";
 	machid = <0x08010000>;
+	config_name = "config@1";
 
 	aliases {
 		console = "/serial@78AF000";
+		mmc = "/sdhci@7804000";
+	};
+
+	mmc: sdhci@7804000 {
+		compatible = "qcom,sdhci-msm";
 	};
 
 	timer {
diff --git a/board/qca/arm/ipq5018/ipq5018.c b/board/qca/arm/ipq5018/ipq5018.c
index dfc827d..90d4ce3 100644
--- a/board/qca/arm/ipq5018/ipq5018.c
+++ b/board/qca/arm/ipq5018/ipq5018.c
@@ -20,9 +20,14 @@
 #include <asm/arch-qca-common/qpic_nand.h>
 #include <asm/arch-qca-common/gpio.h>
 #include <asm/arch-qca-common/uart.h>
+#include <asm/arch-qca-common/scm.h>
+#include <asm/arch-qca-common/iomap.h>
 #include <ipq5018.h>
+#include <mmc.h>
+#include <sdhci.h>
 
 DECLARE_GLOBAL_DATA_PTR;
+struct sdhci_host mmc_host;
 extern int ipq_spi_init(u16);
 
 void uart1_configure_mux(void)
@@ -124,6 +129,162 @@
 	qca_gpio_init(node);
 }
 
+/*
+ * Set the uuid in bootargs variable for mounting rootfilesystem
+ */
+#ifdef CONFIG_QCA_MMC
+int set_uuid_bootargs(char *boot_args, char *part_name, int buflen, bool gpt_flag)
+{
+	int ret, len;
+	block_dev_desc_t *blk_dev;
+	disk_partition_t disk_info;
+
+	blk_dev = mmc_get_dev(mmc_host.dev_num);
+	if (!blk_dev) {
+		printf("Invalid block device name\n");
+		return -EINVAL;
+	}
+
+	if (buflen <= 0 || buflen > MAX_BOOT_ARGS_SIZE)
+		return -EINVAL;
+
+#ifdef CONFIG_PARTITION_UUIDS
+	ret = get_partition_info_efi_by_name(blk_dev,
+			part_name, &disk_info);
+	if (ret) {
+		printf("bootipq: unsupported partition name %s\n",part_name);
+		return -EINVAL;
+	}
+	if ((len = strlcpy(boot_args, "root=PARTUUID=", buflen)) >= buflen)
+		return -EINVAL;
+#else
+	if ((len = strlcpy(boot_args, "rootfsname=", buflen)) >= buflen)
+		return -EINVAL;
+#endif
+	boot_args += len;
+	buflen -= len;
+
+#ifdef CONFIG_PARTITION_UUIDS
+	if ((len = strlcpy(boot_args, disk_info.uuid, buflen)) >= buflen)
+		return -EINVAL;
+#else
+	if ((len = strlcpy(boot_args, part_name, buflen)) >= buflen)
+		return -EINVAL;
+#endif
+	boot_args += len;
+	buflen -= len;
+
+	if (gpt_flag && strlcpy(boot_args, " gpt", buflen) >= buflen)
+		return -EINVAL;
+
+	return 0;
+}
+#else
+int set_uuid_bootargs(char *boot_args, char *part_name, int buflen, bool gpt_flag)
+{
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_QCA_MMC
+void emmc_clock_config(void)
+{
+	/* Enable root clock generator */
+	writel(readl(GCC_SDCC1_APPS_CBCR)|0x1, GCC_SDCC1_APPS_CBCR);
+	/* Add 10us delay for CLK_OFF to get cleared */
+	udelay(10);
+	writel(readl(GCC_SDCC1_AHB_CBCR)|0x1, GCC_SDCC1_AHB_CBCR);
+	/* PLL0 - 192Mhz */
+	writel(0x20B, GCC_SDCC1_APPS_CFG_RCGR);
+	/* Delay for clock operation complete */
+	udelay(10);
+	writel(0x1, GCC_SDCC1_APPS_M);
+	writel(0xFC, GCC_SDCC1_APPS_N);
+	writel(0xFD, GCC_SDCC1_APPS_D);
+	/* Delay for clock operation complete */
+	udelay(10);
+	/* Update APPS_CMD_RCGR to reflect source selection */
+	writel(readl(GCC_SDCC1_APPS_CMD_RCGR)|0x1, GCC_SDCC1_APPS_CMD_RCGR);
+	/* Add 10us delay for clock update to complete */
+	udelay(10);
+}
+
+void mmc_iopad_config(struct sdhci_host *host)
+{
+	u32 val;
+	val = sdhci_readb(host, SDHCI_VENDOR_IOPAD);
+	/*set bit 15 & 16*/
+	val |= 0x18000;
+	writel(val, host->ioaddr + SDHCI_VENDOR_IOPAD);
+}
+
+void sdhci_bus_pwr_off(struct sdhci_host *host)
+{
+	u32 val;
+
+	val = sdhci_readb(host, SDHCI_HOST_CONTROL);
+	sdhci_writeb(host,(val & (~SDHCI_POWER_ON)), SDHCI_POWER_CONTROL);
+}
+
+void emmc_clock_disable(void)
+{
+	/* Clear divider */
+	writel(0x0, GCC_SDCC1_MISC);
+}
+
+void board_mmc_deinit(void)
+{
+	emmc_clock_disable();
+}
+
+void emmc_clock_reset(void)
+{
+	writel(0x1, GCC_SDCC1_BCR);
+	udelay(10);
+	writel(0x0, GCC_SDCC1_BCR);
+}
+
+int board_mmc_init(bd_t *bis)
+{
+	int node;
+	int ret = 0;
+	qca_smem_flash_info_t *sfi = &qca_smem_flash_info;
+
+	node = fdt_path_offset(gd->fdt_blob, "mmc");
+	if (node < 0) {
+		printf("sdhci: Node Not found, skipping initialization\n");
+		return -1;
+	}
+
+	mmc_host.ioaddr = (void *)MSM_SDC1_SDHCI_BASE;
+	mmc_host.voltages = MMC_VDD_165_195;
+	mmc_host.version = SDHCI_SPEC_300;
+	mmc_host.cfg.part_type = PART_TYPE_EFI;
+	mmc_host.quirks = SDHCI_QUIRK_BROKEN_VOLTAGE;
+
+	emmc_clock_disable();
+	emmc_clock_reset();
+	udelay(10);
+	emmc_clock_config();
+
+	if (add_sdhci(&mmc_host, 200000000, 400000)) {
+		printf("add_sdhci fail!\n");
+		return -1;
+	}
+
+	if (!ret && sfi->flash_type == SMEM_BOOT_MMC_FLASH) {
+		ret = board_mmc_env_init(mmc_host);
+	}
+
+	return ret;
+}
+#else
+int board_mmc_init(bd_t *bis)
+{
+	return 0;
+}
+#endif
+
 void reset_crashdump(void)
 {
 	return;
@@ -160,13 +321,6 @@
 	icache_disable();
 	dcache_disable();
 }
-/**
- * * Set the uuid in bootargs variable for mounting rootfilesystem
- */
-int set_uuid_bootargs(char *boot_args, char *part_name, int buflen, bool gpt_flag)
-{
-	return 0;
-}
 
 unsigned long timer_read_counter(void)
 {
diff --git a/board/qca/arm/ipq5018/ipq5018.h b/board/qca/arm/ipq5018/ipq5018.h
index 581cd71..a220312 100644
--- a/board/qca/arm/ipq5018/ipq5018.h
+++ b/board/qca/arm/ipq5018/ipq5018.h
@@ -18,6 +18,23 @@
 #include <asm/u-boot.h>
 #include <asm/arch-qca-common/qca_common.h>
 
+#define MSM_SDC1_BASE			0x7800000
+#define MSM_SDC1_SDHCI_BASE		0x7804000
+
+/*
+ * GCC-SDCC Registers
+ */
+
+#define GCC_SDCC1_BCR			0x01842000
+#define GCC_SDCC1_APPS_CMD_RCGR		0x01842004
+#define GCC_SDCC1_APPS_CFG_RCGR		0x01842008
+#define GCC_SDCC1_APPS_M		0x0184200C
+#define GCC_SDCC1_APPS_N		0x01842010
+#define GCC_SDCC1_APPS_D		0x01842014
+#define GCC_SDCC1_APPS_CBCR		0x01842018
+#define GCC_SDCC1_AHB_CBCR		0x0184201C
+#define GCC_SDCC1_MISC			0x01842020
+
 /* UART 1 */
 #define GCC_BLSP1_UART1_BCR               0x01802038
 #define GCC_BLSP1_UART1_APPS_CBCR         0x0180203C
diff --git a/configs/ipq5018_defconfig b/configs/ipq5018_defconfig
index 89bf236..d0fe426 100644
--- a/configs/ipq5018_defconfig
+++ b/configs/ipq5018_defconfig
@@ -101,6 +101,8 @@
 #
 # CONFIG_CMD_TIME is not set
 CONFIG_CMD_MISC=y
+CONFIG_CMD_PART=y
+CONFIG_PARTITION_UUIDS=y
 # CONFIG_CMD_TIMER is not set
 
 #
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index b1fcd92..a3ec813 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -672,8 +672,11 @@
 
 	if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE)
 		host->cfg.voltages |= host->voltages;
-
-	host->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_8BIT;
+#ifdef CONFIG_MMC_FORCE_CAP_4BIT_BUSWIDTH
+        host->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT;
+#else
+        host->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_8BIT;
+#endif
 	if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
 		if (caps & SDHCI_CAN_DO_8BIT)
 			host->cfg.host_caps |= MMC_MODE_8BIT;
diff --git a/include/configs/ipq5018.h b/include/configs/ipq5018.h
index 32b9b84..e9a893e 100644
--- a/include/configs/ipq5018.h
+++ b/include/configs/ipq5018.h
@@ -152,6 +152,29 @@
 #define CONFIG_QUP_SPI_USE_DMA			1
 #define CONFIG_EFI_PARTITION
 #define CONFIG_QCA_BAM				1
+
+/*
+ * MMC configs
+ */
+#define CONFIG_QCA_MMC
+
+#ifdef CONFIG_QCA_MMC
+#define CONFIG_MMC
+#define CONFIG_CMD_MMC
+#define CONFIG_GENERIC_MMC
+#define CONFIG_SDHCI
+#define CONFIG_SDHCI_QCA
+#define CONFIG_ENV_IS_IN_MMC
+#define CONFIG_SYS_MMC_ENV_DEV			0
+#define CONFIG_SDHCI_SUPPORT
+#define CONFIG_MMC_ADMA
+/*
+* eMMC controller support only 4-bit
+* force SDHC driver to 4-bit mode
+*/
+#define CONFIG_MMC_FORCE_CAP_4BIT_BUSWIDTH
+#endif
+
 /*
 * Expose SPI driver as a pseudo NAND driver to make use
 * of U-Boot's MTD framework.