platform/target: Add clock driver support and enable SDHCI

Add support to enable SDHCI and USB. This patch also
enables the clock driver for various peripherals.

Change-Id: I96d3079b0615cee34c2b3f6d8b2c13517aa5a442
diff --git a/platform/msm8952/acpuclock.c b/platform/msm8952/acpuclock.c
index ffb8b92..0c03f4d 100644
--- a/platform/msm8952/acpuclock.c
+++ b/platform/msm8952/acpuclock.c
@@ -38,24 +38,144 @@
 
 void hsusb_clock_init(void)
 {
+	int ret;
+	struct clk *iclk, *cclk;
 
+	ret = clk_get_set_enable("usb_iface_clk", 0, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set usb_iface_clk ret = %d\n", ret);
+		ASSERT(0);
+	}
+
+	ret = clk_get_set_enable("usb_core_clk", 80000000, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set usb_core_clk ret = %d\n", ret);
+		ASSERT(0);
+	}
+
+	mdelay(20);
+
+	iclk = clk_get("usb_iface_clk");
+	cclk = clk_get("usb_core_clk");
+
+	clk_disable(iclk);
+	clk_disable(cclk);
+
+	mdelay(20);
+
+	/* Start the block reset for usb */
+	writel(1, USB_HS_BCR);
+
+	mdelay(20);
+
+	/* Take usb block out of reset */
+	writel(0, USB_HS_BCR);
+
+	mdelay(20);
+
+	ret = clk_enable(iclk);
+
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set usb_iface_clk after async ret = %d\n", ret);
+		ASSERT(0);
+	}
+
+	ret = clk_enable(cclk);
+
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set usb_iface_clk after async ret = %d\n", ret);
+		ASSERT(0);
+	}
 }
 
 void clock_init_mmc(uint32_t interface)
 {
+	char clk_name[64];
+	int ret;
 
+	snprintf(clk_name, sizeof(clk_name), "sdc%u_iface_clk", interface);
+
+	/* enable interface clock */
+	ret = clk_get_set_enable(clk_name, 0, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set sdc1_iface_clk ret = %d\n", ret);
+		ASSERT(0);
+	}
 }
 
 /* Configure MMC clock */
 void clock_config_mmc(uint32_t interface, uint32_t freq)
 {
-	mmc_boot_mci_clk_enable();
+	int ret = 1;
+	char clk_name[64];
+
+	snprintf(clk_name, sizeof(clk_name), "sdc%u_core_clk", interface);
+
+	if(freq == MMC_CLK_400KHZ)
+	{
+		ret = clk_get_set_enable(clk_name, 400000, 1);
+	}
+	else if(freq == MMC_CLK_50MHZ)
+	{
+		ret = clk_get_set_enable(clk_name, 50000000, 1);
+	}
+	else if(freq == MMC_CLK_177MHZ)
+	{
+		ret = clk_get_set_enable(clk_name, 177770000, 1);
+	}
+	else if(freq == MMC_CLK_192MHZ)
+	{
+		ret = clk_get_set_enable(clk_name, 192000000, 1);
+	}
+	else if(freq == MMC_CLK_200MHZ)
+	{
+		ret = clk_get_set_enable(clk_name, 200000000, 1);
+	}
+	else if(freq == MMC_CLK_400MHZ)
+	{
+		ret = clk_get_set_enable(clk_name, 384000000, 1);
+	}
+	else
+	{
+		dprintf(CRITICAL, "sdc frequency (%u) is not supported\n", freq);
+		ASSERT(0);
+	}
+
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set %s ret = %d\n", clk_name, ret);
+		ASSERT(0);
+	}
 }
 
 /* Configure UART clock based on the UART block id*/
 void clock_config_uart_dm(uint8_t id)
 {
+	int ret;
+	char iclk[64];
+	char cclk[64];
 
+	snprintf(iclk, sizeof(iclk), "uart%u_iface_clk", id);
+	snprintf(cclk, sizeof(cclk), "uart%u_core_clk", id);
+
+	ret = clk_get_set_enable(iclk, 0, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set %s ret = %d\n", iclk, ret);
+		ASSERT(0);
+	}
+
+	ret = clk_get_set_enable(cclk, 7372800, 1);
+	if(ret)
+	{
+		dprintf(CRITICAL, "failed to set %s ret = %d\n", cclk, ret);
+		ASSERT(0);
+	}
 }
 
 /* Function to asynchronously reset CE.
diff --git a/platform/msm8952/include/platform/iomap.h b/platform/msm8952/include/platform/iomap.h
index ac40933..f4712d7 100644
--- a/platform/msm8952/include/platform/iomap.h
+++ b/platform/msm8952/include/platform/iomap.h
@@ -62,6 +62,7 @@
 #define MSM_SDC1_BASE                      (PERIPH_SS_BASE + 0x00024000)
 #define MSM_SDC2_BASE                      (PERIPH_SS_BASE + 0x00064000)
 
+/* UART */
 #define BLSP1_UART0_BASE                   (PERIPH_SS_BASE + 0x000AF000)
 #define BLSP1_UART1_BASE                   (PERIPH_SS_BASE + 0x000B0000)
 #define MSM_USB_BASE                       (PERIPH_SS_BASE + 0x000DB000)
@@ -84,12 +85,18 @@
 /* CRYPTO ENGINE */
 #define  MSM_CE1_BASE                      0x073A000
 #define  MSM_CE1_BAM_BASE                  0x0704000
-
+#define  GCC_CRYPTO_BCR                    (CLK_CTL_BASE + 0x16000)
+#define  GCC_CRYPTO_CMD_RCGR               (CLK_CTL_BASE + 0x16004)
+#define  GCC_CRYPTO_CFG_RCGR               (CLK_CTL_BASE + 0x16008)
+#define  GCC_CRYPTO_CBCR                   (CLK_CTL_BASE + 0x1601C)
+#define  GCC_CRYPTO_AXI_CBCR               (CLK_CTL_BASE + 0x16020)
+#define  GCC_CRYPTO_AHB_CBCR               (CLK_CTL_BASE + 0x16024)
 
 /* GPLL */
 #define GPLL0_STATUS                       (CLK_CTL_BASE + 0x2101C)
 #define APCS_GPLL_ENA_VOTE                 (CLK_CTL_BASE + 0x45000)
 #define APCS_CLOCK_BRANCH_ENA_VOTE         (CLK_CTL_BASE + 0x45004)
+#define GPLL4_MODE                         (CLK_CTL_BASE + 0x24000)
 
 /* SDCC */
 #define SDC1_HDRV_PULL_CTL                 (TLMM_BASE_ADDR + 0x10A000)
@@ -102,6 +109,25 @@
 #define SDCC1_N                            (CLK_CTL_BASE + 0x42010) /* n */
 #define SDCC1_D                            (CLK_CTL_BASE + 0x42014) /* d */
 
+/* SDHCI */
+#define MSM_SDC1_SDHCI_BASE                (PERIPH_SS_BASE + 0x00024900)
+#define MSM_SDC2_SDHCI_BASE                (PERIPH_SS_BASE + 0x00064900)
+
+#define SDCC_MCI_HC_MODE                   (0x00000078)
+#define SDCC_HC_PWRCTL_STATUS_REG          (0x000000DC)
+#define SDCC_HC_PWRCTL_MASK_REG            (0x000000E0)
+#define SDCC_HC_PWRCTL_CLEAR_REG           (0x000000E4)
+#define SDCC_HC_PWRCTL_CTL_REG             (0x000000E8)
+
+#define SDCC2_BCR                          (CLK_CTL_BASE + 0x43000) /* block reset */
+#define SDCC2_APPS_CBCR                    (CLK_CTL_BASE + 0x43018) /* branch control */
+#define SDCC2_AHB_CBCR                     (CLK_CTL_BASE + 0x4301C)
+#define SDCC2_CMD_RCGR                     (CLK_CTL_BASE + 0x43004) /* cmd */
+#define SDCC2_CFG_RCGR                     (CLK_CTL_BASE + 0x43008) /* cfg */
+#define SDCC2_M                            (CLK_CTL_BASE + 0x4300C) /* m */
+#define SDCC2_N                            (CLK_CTL_BASE + 0x43010) /* n */
+#define SDCC2_D                            (CLK_CTL_BASE + 0x43014) /* d */
+
 /* UART */
 #define BLSP1_AHB_CBCR                     (CLK_CTL_BASE + 0x1008)
 #define BLSP1_UART2_APPS_CBCR              (CLK_CTL_BASE + 0x302C)
diff --git a/platform/msm8952/include/platform/irqs.h b/platform/msm8952/include/platform/irqs.h
index 31da373..810f113 100644
--- a/platform/msm8952/include/platform/irqs.h
+++ b/platform/msm8952/include/platform/irqs.h
@@ -46,6 +46,8 @@
 
 #define USB1_HS_BAM_IRQ                        (GIC_SPI_START + 135)
 #define USB1_HS_IRQ                            (GIC_SPI_START + 134)
+#define SDCC1_PWRCTL_IRQ                       (GIC_SPI_START + 138)
+#define SDCC2_PWRCTL_IRQ                       (GIC_SPI_START + 221)
 
 /* Retrofit universal macro names */
 #define INT_USB_HS                             USB1_HS_IRQ
diff --git a/platform/msm8952/msm8952-clock.c b/platform/msm8952/msm8952-clock.c
index ed39611..f464cc8 100644
--- a/platform/msm8952/msm8952-clock.c
+++ b/platform/msm8952/msm8952-clock.c
@@ -111,6 +111,21 @@
 	},
 };
 
+static struct pll_vote_clk gpll4_clk_src =
+{
+	.en_reg       = (void *) APCS_GPLL_ENA_VOTE,
+	.en_mask      = BIT(5),
+	.status_reg   = (void *) GPLL4_MODE,
+	.status_mask  = BIT(30),
+	.parent       = &cxo_clk_src.c,
+
+	.c = {
+		.rate     = 1152000000,
+		.dbg_name = "gpll4_clk_src",
+		.ops      = &clk_ops_pll_vote,
+	},
+};
+
 /* SDCC Clocks */
 static struct clk_freq_tbl ftbl_gcc_sdcc1_apps_clk[] =
 {
@@ -121,8 +136,8 @@
 	F( 50000000,  gpll0,  16,   0,   0),
 	F(100000000,  gpll0,   8,   0,   0),
 	F(177770000,  gpll0, 4.5,   0,   0),
-	F(200000000,  gpll0,   4,   0,   0),
-	F(400000000,  gpll4,   3,   0,   0),
+	F(192000000,  gpll0,   6,   0,   0),
+	F(384000000,  gpll4,   3,   0,   0),
 	F_END
 };
 
@@ -135,7 +150,7 @@
 	.d_reg        = (uint32_t *) SDCC1_D,
 
 	.set_rate     = clock_lib2_rcg_set_rate_mnd,
-	.freq_tbl     = ftbl_gcc_sdcc1_2_apps_clk,
+	.freq_tbl     = ftbl_gcc_sdcc1_apps_clk,
 	.current_freq = &rcg_dummy_freq,
 
 	.c = {
diff --git a/platform/msm8952/platform.c b/platform/msm8952/platform.c
index 4648638..1ee7cdc 100644
--- a/platform/msm8952/platform.c
+++ b/platform/msm8952/platform.c
@@ -29,12 +29,16 @@
 #include <debug.h>
 #include <reg.h>
 #include <platform/iomap.h>
+#include <platform/irqs.h>
+#include <platform/clock.h>
 #include <qgic.h>
 #include <qtimer.h>
 #include <mmu.h>
 #include <arch/arm/mmu.h>
 #include <smem.h>
 #include <board.h>
+#include <boot_stats.h>
+#include <platform.h>
 
 #define MSM_IOMAP_SIZE ((MSM_IOMAP_END - MSM_IOMAP_BASE)/MB)
 #define APPS_SS_SIZE   ((APPS_SS_END - APPS_SS_BASE)/MB)
@@ -66,6 +70,7 @@
 void platform_early_init(void)
 {
 	board_init();
+	platform_clock_init();
 	qgic_init();
 	qtimer_init();
 	scm_init();
diff --git a/platform/msm8952/rules.mk b/platform/msm8952/rules.mk
index ebae71e..fbbece0 100644
--- a/platform/msm8952/rules.mk
+++ b/platform/msm8952/rules.mk
@@ -19,6 +19,7 @@
 OBJS += \
        $(LOCAL_DIR)/platform.o \
        $(LOCAL_DIR)/acpuclock.o \
+       $(LOCAL_DIR)/msm8952-clock.o \
        $(LOCAL_DIR)/gpio.o
 
 LINKER_SCRIPT += $(BUILDDIR)/system-onesegment.ld
diff --git a/target/msm8952/init.c b/target/msm8952/init.c
index c61c631..3893d9a 100644
--- a/target/msm8952/init.c
+++ b/target/msm8952/init.c
@@ -60,23 +60,82 @@
 #define FASTBOOT_MODE           0x77665500
 #define PON_SOFT_RB_SPARE       0x88F
 
-static uint32_t mmc_sdc_base[] =
+struct mmc_device *dev;
+
+static uint32_t mmc_pwrctl_base[] =
 	{ MSM_SDC1_BASE, MSM_SDC2_BASE };
 
+static uint32_t mmc_sdhci_base[] =
+	{ MSM_SDC1_SDHCI_BASE, MSM_SDC2_SDHCI_BASE };
+
+static uint32_t  mmc_sdc_pwrctl_irq[] =
+	{ SDCC1_PWRCTL_IRQ, SDCC2_PWRCTL_IRQ };
 
 void target_early_init(void)
 {
 #if WITH_DEBUG_UART
-	uart_dm_init(1, 0, BLSP1_UART1_BASE);
+	uart_dm_init(2, 0, BLSP1_UART1_BASE);
 #endif
 }
 
-void target_mmc_caps(struct mmc_host *host)
+static void set_sdc_power_ctrl()
 {
-	host->caps.ddr_mode = 0;
-	host->caps.hs200_mode = 0;
-	host->caps.bus_width = MMC_BOOT_BUS_WIDTH_8_BIT;
-	host->caps.hs_clk_rate = MMC_CLK_50MHZ;
+	/* Drive strength configs for sdc pins */
+	struct tlmm_cfgs sdc1_hdrv_cfg[] =
+	{
+		{ SDC1_CLK_HDRV_CTL_OFF,  TLMM_CUR_VAL_16MA, TLMM_HDRV_MASK, 0},
+		{ SDC1_CMD_HDRV_CTL_OFF,  TLMM_CUR_VAL_10MA, TLMM_HDRV_MASK, 0},
+		{ SDC1_DATA_HDRV_CTL_OFF, TLMM_CUR_VAL_10MA, TLMM_HDRV_MASK , 0},
+	};
+
+	/* Pull configs for sdc pins */
+	struct tlmm_cfgs sdc1_pull_cfg[] =
+	{
+		{ SDC1_CLK_PULL_CTL_OFF,  TLMM_NO_PULL, TLMM_PULL_MASK, 0},
+		{ SDC1_CMD_PULL_CTL_OFF,  TLMM_PULL_UP, TLMM_PULL_MASK, 0},
+		{ SDC1_DATA_PULL_CTL_OFF, TLMM_PULL_UP, TLMM_PULL_MASK, 0},
+	};
+
+	/* Set the drive strength & pull control values */
+	tlmm_set_hdrive_ctrl(sdc1_hdrv_cfg, ARRAY_SIZE(sdc1_hdrv_cfg));
+	tlmm_set_pull_ctrl(sdc1_pull_cfg, ARRAY_SIZE(sdc1_pull_cfg));
+}
+
+void target_sdc_init()
+{
+	struct mmc_config_data config;
+
+	/* Set drive strength & pull ctrl values */
+	set_sdc_power_ctrl();
+
+	/* Try slot 1*/
+	config.slot          = 1;
+	config.bus_width     = DATA_BUS_WIDTH_8BIT;
+	config.max_clk_rate  = MMC_CLK_177MHZ;
+	config.sdhc_base     = mmc_sdhci_base[config.slot - 1];
+	config.pwrctl_base   = mmc_pwrctl_base[config.slot - 1];
+	config.pwr_irq       = mmc_sdc_pwrctl_irq[config.slot - 1];
+	config.hs400_support = 1;
+
+	if (!(dev = mmc_init(&config))) {
+	/* Try slot 2 */
+		config.slot          = 2;
+		config.max_clk_rate  = MMC_CLK_200MHZ;
+		config.sdhc_base     = mmc_sdhci_base[config.slot - 1];
+		config.pwrctl_base   = mmc_pwrctl_base[config.slot - 1];
+		config.pwr_irq       = mmc_sdc_pwrctl_irq[config.slot - 1];
+		config.hs400_support = 0;
+
+		if (!(dev = mmc_init(&config))) {
+			dprintf(CRITICAL, "mmc init failed!");
+			ASSERT(0);
+		}
+	}
+}
+
+void *target_mmc_device()
+{
+	return (void *) dev;
 }
 
 /* Return 1 if vol_up pressed */
@@ -144,20 +203,13 @@
 
 	target_keystatus();
 
-	/* Trying Slot 1*/
-	slot = 1;
-	base_addr = mmc_sdc_base[slot - 1];
-	if (mmc_boot_main(slot, base_addr))
+	target_sdc_init();
+	if (partition_read_table())
 	{
-
-	/* Trying Slot 2 next */
-	slot = 2;
-	base_addr = mmc_sdc_base[slot - 1];
-	if (mmc_boot_main(slot, base_addr)) {
-		dprintf(CRITICAL, "mmc init failed!");
+		dprintf(CRITICAL, "Error reading the partition table info\n");
 		ASSERT(0);
-		}
 	}
+
 #if LONG_PRESS_POWER_ON
 	shutdown_detect();
 #endif
@@ -314,8 +366,37 @@
 	if (is_cold_boot &&
 			(!(pon_reason & HARD_RST)) &&
 			(!(pon_reason & KPDPWR_N)) &&
-			((pon_reason & USB_CHG) || (pon_reason & DC_CHG) || (pon_reason & CBLPWR_N)))
+			((pon_reason & USB_CHG)))
 		return 1;
 	else
 		return 0;
 }
+
+void target_uninit(void)
+{
+	mmc_put_card_to_sleep(dev);
+	sdhci_mode_disable(&dev->host);
+}
+
+void target_usb_init(void)
+{
+	uint32_t val;
+
+	/* Select and enable external configuration with USB PHY */
+	ulpi_write(ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT, ULPI_MISC_A_SET);
+
+	/* Enable sess_vld */
+	val = readl(USB_GENCONFIG_2) | GEN2_SESS_VLD_CTRL_EN;
+	writel(val, USB_GENCONFIG_2);
+
+	/* Enable external vbus configuration in the LINK */
+	val = readl(USB_USBCMD);
+	val |= SESS_VLD_CTRL;
+	writel(val, USB_USBCMD);
+}
+
+void target_usb_stop(void)
+{
+	/* Disable VBUS mimicing in the controller. */
+	ulpi_write(ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT, ULPI_MISC_A_CLEAR);
+}