Merge "target: msm8974: Add support to use different sdc instances"
diff --git a/dev/pmic/pm8x41/include/pm8x41.h b/dev/pmic/pm8x41/include/pm8x41.h
index 731528c..b230549 100644
--- a/dev/pmic/pm8x41/include/pm8x41.h
+++ b/dev/pmic/pm8x41/include/pm8x41.h
@@ -61,6 +61,7 @@
#define PON_PSHOLD_WARM_RESET 0x1
#define PON_PSHOLD_SHUTDOWN 0x4
+#define PON_PSHOLD_HARD_RESET 0x7
enum PM8X41_VERSIONS
{
diff --git a/platform/msm8226/include/platform/iomap.h b/platform/msm8226/include/platform/iomap.h
index ea8bbeb..5418229 100644
--- a/platform/msm8226/include/platform/iomap.h
+++ b/platform/msm8226/include/platform/iomap.h
@@ -128,6 +128,17 @@
#define SDCC1_N (CLK_CTL_BASE + 0x4DC) /* n */
#define SDCC1_D (CLK_CTL_BASE + 0x4E0) /* d */
+/* SDCC2 */
+#define SDCC2_BCR (CLK_CTL_BASE + 0x500) /* block reset */
+#define SDCC2_APPS_CBCR (CLK_CTL_BASE + 0x504) /* branch control */
+#define SDCC2_AHB_CBCR (CLK_CTL_BASE + 0x508)
+#define SDCC2_INACTIVITY_TIMER_CBCR (CLK_CTL_BASE + 0x50C)
+#define SDCC2_CMD_RCGR (CLK_CTL_BASE + 0x510) /* cmd */
+#define SDCC2_CFG_RCGR (CLK_CTL_BASE + 0x514) /* cfg */
+#define SDCC2_M (CLK_CTL_BASE + 0x518) /* m */
+#define SDCC2_N (CLK_CTL_BASE + 0x51C) /* n */
+#define SDCC2_D (CLK_CTL_BASE + 0x520) /* d */
+
/* UART */
#define BLSP1_AHB_CBCR (CLK_CTL_BASE + 0x5C4)
#define BLSP1_UART3_APPS_CBCR (CLK_CTL_BASE + 0x784)
@@ -144,9 +155,11 @@
#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)
+#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)
/* DRV strength for sdcc */
#define SDC1_HDRV_PULL_CTL (TLMM_BASE_ADDR + 0x00002044)
diff --git a/platform/msm8226/include/platform/irqs.h b/platform/msm8226/include/platform/irqs.h
index 2e29d3a..c3abd2f 100644
--- a/platform/msm8226/include/platform/irqs.h
+++ b/platform/msm8226/include/platform/irqs.h
@@ -47,7 +47,9 @@
#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)
+#define SDCC1_PWRCTL_IRQ (GIC_SPI_START + 138)
+#define SDCC2_PWRCTL_IRQ (GIC_SPI_START + 221)
+#define SDCC3_PWRCTL_IRQ (GIC_SPI_START + 224)
/* Retrofit universal macro names */
#define INT_USB_HS USB1_HS_IRQ
diff --git a/platform/msm8226/msm8226-clock.c b/platform/msm8226/msm8226-clock.c
index bd0a265..4c4758d 100644
--- a/platform/msm8226/msm8226-clock.c
+++ b/platform/msm8226/msm8226-clock.c
@@ -166,6 +166,46 @@
},
};
+static struct rcg_clk sdcc2_apps_clk_src =
+{
+ .cmd_reg = (uint32_t *) SDCC2_CMD_RCGR,
+ .cfg_reg = (uint32_t *) SDCC2_CFG_RCGR,
+ .m_reg = (uint32_t *) SDCC2_M,
+ .n_reg = (uint32_t *) SDCC2_N,
+ .d_reg = (uint32_t *) SDCC2_D,
+
+ .set_rate = clock_lib2_rcg_set_rate_mnd,
+ .freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+
+ .c = {
+ .dbg_name = "sdc2_clk",
+ .ops = &clk_ops_rcg_mnd,
+ },
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk =
+{
+ .cbcr_reg = (uint32_t *) SDCC2_APPS_CBCR,
+ .parent = &sdcc2_apps_clk_src.c,
+
+ .c = {
+ .dbg_name = "gcc_sdcc2_apps_clk",
+ .ops = &clk_ops_branch,
+ },
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk =
+{
+ .cbcr_reg = (uint32_t *) SDCC2_AHB_CBCR,
+ .has_sibling = 1,
+
+ .c = {
+ .dbg_name = "gcc_sdcc2_ahb_clk",
+ .ops = &clk_ops_branch,
+ },
+};
+
/* UART Clocks */
static struct clk_freq_tbl ftbl_gcc_blsp1_2_uart1_6_apps_clk[] =
{
@@ -487,6 +527,9 @@
CLK_LOOKUP("sdc1_iface_clk", gcc_sdcc1_ahb_clk.c),
CLK_LOOKUP("sdc1_core_clk", gcc_sdcc1_apps_clk.c),
+ CLK_LOOKUP("sdc2_iface_clk", gcc_sdcc2_ahb_clk.c),
+ CLK_LOOKUP("sdc2_core_clk", gcc_sdcc2_apps_clk.c),
+
CLK_LOOKUP("uart3_iface_clk", gcc_blsp1_ahb_clk.c),
CLK_LOOKUP("uart3_core_clk", gcc_blsp1_uart3_apps_clk.c),
diff --git a/platform/msm8974/include/platform/iomap.h b/platform/msm8974/include/platform/iomap.h
index 799fc86..3e27c3b 100644
--- a/platform/msm8974/include/platform/iomap.h
+++ b/platform/msm8974/include/platform/iomap.h
@@ -139,6 +139,17 @@
#define SDCC1_N (CLK_CTL_BASE + 0x4DC) /* n */
#define SDCC1_D (CLK_CTL_BASE + 0x4E0) /* d */
+/* SDCC2 */
+#define SDCC2_BCR (CLK_CTL_BASE + 0x500) /* block reset */
+#define SDCC2_APPS_CBCR (CLK_CTL_BASE + 0x504) /* branch control */
+#define SDCC2_AHB_CBCR (CLK_CTL_BASE + 0x508)
+#define SDCC2_INACTIVITY_TIMER_CBCR (CLK_CTL_BASE + 0x50C)
+#define SDCC2_CMD_RCGR (CLK_CTL_BASE + 0x510) /* cmd */
+#define SDCC2_CFG_RCGR (CLK_CTL_BASE + 0x514) /* cfg */
+#define SDCC2_M (CLK_CTL_BASE + 0x518) /* m */
+#define SDCC2_N (CLK_CTL_BASE + 0x51C) /* n */
+#define SDCC2_D (CLK_CTL_BASE + 0x520) /* d */
+
/* UART */
#define BLSP1_AHB_CBCR (CLK_CTL_BASE + 0x5C4)
#define BLSP2_AHB_CBCR (CLK_CTL_BASE + 0x944)
@@ -206,7 +217,9 @@
#define SDC1_HDRV_PULL_CTL (TLMM_BASE_ADDR + 0x00002044)
/* 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)
+#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)
#endif
diff --git a/platform/msm8974/include/platform/irqs.h b/platform/msm8974/include/platform/irqs.h
index 56ef1cb..e9b2d06 100644
--- a/platform/msm8974/include/platform/irqs.h
+++ b/platform/msm8974/include/platform/irqs.h
@@ -66,5 +66,8 @@
((GIC_SPI_START + 95) + qup_id):\
((GIC_SPI_START + 101) + qup_id))
-#define SDCC_PWRCTRL_IRQ (GIC_SPI_START + 138)
+#define SDCC1_PWRCTL_IRQ (GIC_SPI_START + 138)
+#define SDCC2_PWRCTL_IRQ (GIC_SPI_START + 221)
+#define SDCC3_PWRCTL_IRQ (GIC_SPI_START + 224)
+#define SDCC4_PWRCTL_IRQ (GIC_SPI_START + 227)
#endif /* __IRQS_COPPER_H */
diff --git a/platform/msm8974/msm8974-clock.c b/platform/msm8974/msm8974-clock.c
index 6c88589..dbba8c4 100644
--- a/platform/msm8974/msm8974-clock.c
+++ b/platform/msm8974/msm8974-clock.c
@@ -166,6 +166,46 @@
},
};
+static struct rcg_clk sdcc2_apps_clk_src =
+{
+ .cmd_reg = (uint32_t *) SDCC2_CMD_RCGR,
+ .cfg_reg = (uint32_t *) SDCC2_CFG_RCGR,
+ .m_reg = (uint32_t *) SDCC2_M,
+ .n_reg = (uint32_t *) SDCC2_N,
+ .d_reg = (uint32_t *) SDCC2_D,
+
+ .set_rate = clock_lib2_rcg_set_rate_mnd,
+ .freq_tbl = ftbl_gcc_sdcc1_2_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+
+ .c = {
+ .dbg_name = "sdc2_clk",
+ .ops = &clk_ops_rcg_mnd,
+ },
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk =
+{
+ .cbcr_reg = (uint32_t *) SDCC2_APPS_CBCR,
+ .parent = &sdcc2_apps_clk_src.c,
+
+ .c = {
+ .dbg_name = "gcc_sdcc2_apps_clk",
+ .ops = &clk_ops_branch,
+ },
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk =
+{
+ .cbcr_reg = (uint32_t *) SDCC2_AHB_CBCR,
+ .has_sibling = 1,
+
+ .c = {
+ .dbg_name = "gcc_sdcc2_ahb_clk",
+ .ops = &clk_ops_branch,
+ },
+};
+
/* UART Clocks */
static struct clk_freq_tbl ftbl_gcc_blsp1_2_uart1_6_apps_clk[] =
{
@@ -590,6 +630,9 @@
CLK_LOOKUP("sdc1_iface_clk", gcc_sdcc1_ahb_clk.c),
CLK_LOOKUP("sdc1_core_clk", gcc_sdcc1_apps_clk.c),
+ CLK_LOOKUP("sdc2_iface_clk", gcc_sdcc2_ahb_clk.c),
+ CLK_LOOKUP("sdc2_core_clk", gcc_sdcc2_apps_clk.c),
+
CLK_LOOKUP("uart2_iface_clk", gcc_blsp1_ahb_clk.c),
CLK_LOOKUP("uart2_core_clk", gcc_blsp1_uart2_apps_clk.c),
diff --git a/platform/msm_shared/display.c b/platform/msm_shared/display.c
index 026142c..9254a78 100755
--- a/platform/msm_shared/display.c
+++ b/platform/msm_shared/display.c
@@ -283,7 +283,7 @@
ret = mdp_dsi_video_off();
if (ret)
goto msm_display_off_out;
- ret = mipi_dsi_off();
+ ret = mipi_dsi_off(pinfo);
if (ret)
goto msm_display_off_out;
break;
@@ -292,7 +292,7 @@
ret = mdp_dsi_cmd_off();
if (ret)
goto msm_display_off_out;
- ret = mipi_dsi_off();
+ ret = mipi_dsi_off(pinfo);
if (ret)
goto msm_display_off_out;
break;
diff --git a/platform/msm_shared/include/mipi_dsi.h b/platform/msm_shared/include/mipi_dsi.h
index 6a00efa..4f90f96 100755
--- a/platform/msm_shared/include/mipi_dsi.h
+++ b/platform/msm_shared/include/mipi_dsi.h
@@ -1000,7 +1000,7 @@
unsigned char eof_bllp_pwr,
unsigned char interleav);
int mipi_dsi_on();
-int mipi_dsi_off();
+int mipi_dsi_off(struct msm_panel_info *pinfo);
int mipi_dsi_cmds_tx(struct mipi_dsi_cmd *cmds, int count);
int mipi_dsi_cmds_rx(char **rp, int len);
#endif
diff --git a/platform/msm_shared/include/mmc_sdhci.h b/platform/msm_shared/include/mmc_sdhci.h
index 6aa323d..79d3965 100644
--- a/platform/msm_shared/include/mmc_sdhci.h
+++ b/platform/msm_shared/include/mmc_sdhci.h
@@ -143,6 +143,44 @@
#define MMC_ADDR_OUT_OF_RANGE(resp) ((resp >> 31) & 0x01)
+/* SD card related Macros */
+/* Arguments for commands */
+#define MMC_SD_HC_VOLT_SUPPLIED 0x000001AA
+#define MMC_SD_OCR 0x00FF8000
+#define MMC_SD_HC_HCS 0x40000000
+#define MMC_SD_DEV_READY 0x80000000
+#define MMC_CARD_TYPE_SDHC 0x1
+#define MMC_CARD_TYPE_STD_SD 0x0
+#define SD_CARD_RCA 0x0
+#define MMC_SD_SWITCH_HS 0x80FFFFF1
+
+#define SD_CMD8_MAX_RETRY 0x3
+#define SD_ACMD41_MAX_RETRY 0x14
+
+/* SCR(SD Card Register) related */
+#define SD_SCR_BUS_WIDTH 16
+#define SD_SCR_SD_SPEC 24
+#define SD_SCR_SD_SPEC3 15
+#define SD_SCR_BUS_WIDTH_MASK 0xf0000
+#define SD_SCR_SD_SPEC_MASK 0x0f000000
+#define SD_SCR_SD_SPEC3_MASK 0x8000
+#define SD_SCR_CMD23_SUPPORT BIT(1)
+#define SD_SCR_WIDTH_4BIT BIT(2)
+
+/* SSR related macros */
+#define MMC_SD_AU_SIZE_BIT 428
+#define MMC_SD_AU_SIZE_LEN 4
+#define MMC_SD_ERASE_SIZE_BIT 408
+#define MMC_SD_ERASE_SIZE_LEN 16
+
+/* Commands for SD card */
+#define CMD8_SEND_IF_COND 8
+#define ACMD6_SET_BUS_WIDTH 6
+#define ACMD13_SEND_SD_STATUS 13
+#define ACMD41_SEND_OP_COND 41
+#define ACMD51_READ_CARD_SCR 51
+#define CMD55_APP_CMD 55
+
/* Can be used to unpack array of upto 32 bits data */
#define UNPACK_BITS(array, start, len, size_of) \
({ \
@@ -156,6 +194,20 @@
unpck & mask; \
})
+#define swap_endian32(x) \
+ ((uint32_t)( \
+ (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
+ (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
+ (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
+ (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
+
+
+#define MMC_CARD_SD(card) ((card->type == MMC_CARD_TYPE_SDHC) || \
+ (card->type == MMC_CARD_TYPE_STD_SD))
+
+#define MMC_CARD_MMC(card) ((card->type == MMC_TYPE_STD_MMC) || \
+ (card->type == MMC_TYPE_MMCHC))
+
/* CSD Register.
* Note: not all the fields have been defined here
*/
@@ -196,6 +248,20 @@
uint32_t year; /* 4 bits manufacturing year */
};
+/* SCR register for SD card */
+struct mmc_sd_scr {
+ uint32_t bus_widths; /* Bus width support, 8 or 1 bit */
+ uint32_t sd_spec; /* sd spec version */
+ uint32_t sd3_spec; /* sd spec 3 version */
+ uint32_t cmd23_support; /* cmd23 supported or not */
+};
+
+/* SD Status Register */
+struct mmc_sd_ssr {
+ uint32_t au_size; /* Allocation unit (AU) size */
+ uint32_t num_aus; /* Number of AUs */
+};
+
/* mmc card register */
struct mmc_card {
uint32_t rca; /* Relative addres of the card*/
@@ -205,14 +271,19 @@
uint32_t status; /* Card status */
uint8_t *ext_csd; /* Ext CSD for the card info */
uint32_t raw_csd[4]; /* Raw CSD for the card */
+ uint32_t raw_scr[2]; /* SCR for SD card */
struct mmc_cid cid; /* CID structure */
struct mmc_csd csd; /* CSD structure */
+ struct mmc_sd_scr scr; /* SCR structure */
+ struct mmc_sd_ssr ssr; /* SSR Register */
};
/* mmc device config data */
struct mmc_config_data {
uint8_t slot; /* Sdcc slot used */
- uint32_t base; /* Based address for the sdcc */
+ uint8_t pwr_irq; /* Power Irq from card to host */
+ uint32_t sdhc_base; /* Base address for the sdhc */
+ uint32_t pwrctl_base; /* Base address for power control registers */
uint16_t bus_width; /* Bus width used */
uint32_t max_clk_rate; /* Max clock rate supported */
};
diff --git a/platform/msm_shared/include/sdhci.h b/platform/msm_shared/include/sdhci.h
index 20861fc..ef48d1d 100644
--- a/platform/msm_shared/include/sdhci.h
+++ b/platform/msm_shared/include/sdhci.h
@@ -31,6 +31,7 @@
#include <reg.h>
#include <bits.h>
+#include <kernel/event.h>
/*
* Capabilities for the host controller
@@ -55,6 +56,7 @@
struct sdhci_host {
uint32_t base; /* Base address for the host */
uint32_t cur_clk_rate; /* Running clock rate */
+ event_t* sdhc_event; /* Event for power control irqs */
struct host_caps caps; /* Host capabilities */
};
@@ -79,6 +81,7 @@
uint32_t resp[4]; /* 128 bit response value */
uint32_t trans_mode; /* Transfer mode, read/write */
uint32_t cmd_retry; /* Retry the command, if card is busy */
+ uint32_t cmd23_support; /* If card supports cmd23 */
struct mmc_data data; /* Data pointer */
};
@@ -239,6 +242,7 @@
#define SDHCI_BLK_CNT_EN BIT(1)
#define SDHCI_DMA_EN BIT(0)
#define SDHCI_AUTO_CMD23_EN BIT(3)
+#define SDHCI_AUTO_CMD12_EN BIT(2)
#define SDHCI_ADMA_32BIT BIT(4)
/*
diff --git a/platform/msm_shared/include/sdhci_msm.h b/platform/msm_shared/include/sdhci_msm.h
new file mode 100644
index 0000000..1d77823
--- /dev/null
+++ b/platform/msm_shared/include/sdhci_msm.h
@@ -0,0 +1,43 @@
+/* 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.
+ */
+
+#ifndef __SDHCI_MSM_H__
+#define __SDHCI_MSM_H__
+
+#include <kernel/event.h>
+
+struct sdhci_msm_data
+{
+ uint32_t pwrctl_base;
+ uint32_t pwr_irq;
+ event_t* sdhc_event;
+};
+
+void sdhci_msm_init(struct sdhci_msm_data *data);
+
+#endif
diff --git a/platform/msm_shared/mipi_dsi.c b/platform/msm_shared/mipi_dsi.c
index bbda314..43559eb 100644
--- a/platform/msm_shared/mipi_dsi.c
+++ b/platform/msm_shared/mipi_dsi.c
@@ -1175,7 +1175,7 @@
return ret;
}
-int mipi_dsi_off()
+int mipi_dsi_off(struct msm_panel_info *pinfo)
{
if(!target_cont_splash_screen())
{
@@ -1189,6 +1189,8 @@
}
writel(0x1115501, DSI_INT_CTRL);
+ if (pinfo->mipi.broadcast)
+ writel(0x1115501, DSI_INT_CTRL + 0x600);
return NO_ERROR;
}
diff --git a/platform/msm_shared/mmc_sdhci.c b/platform/msm_shared/mmc_sdhci.c
index d4b0bd4..cb00a3c 100644
--- a/platform/msm_shared/mmc_sdhci.c
+++ b/platform/msm_shared/mmc_sdhci.c
@@ -32,6 +32,7 @@
#include <reg.h>
#include <mmc_sdhci.h>
#include <sdhci.h>
+#include <sdhci_msm.h>
#include <partition_parser.h>
#include <platform/iomap.h>
#include <platform/timer.h>
@@ -85,8 +86,7 @@
mmc_csd.cmmc_structure = UNPACK_BITS(raw_csd, 126, 2, mmc_sizeof);
- if ((card->type == MMC_TYPE_SDHC)
- || (card->type == MMC_TYPE_STD_SD)) {
+ if (MMC_CARD_SD(card)) {
/* Parse CSD according to SD card spec. */
/* CSD register is little bit differnet for CSD version 2.0 High
@@ -133,7 +133,7 @@
mmc_csd.temp_wp = UNPACK_BITS(raw_csd, 12, 1, mmc_sizeof);
/* Calculate the card capcity */
- card->capacity = (1 + mmc_csd.c_size) * 512 * 1024;
+ card->capacity = (unsigned long long) (1 + mmc_csd.c_size) * 512 * 1024;
} else {
/* CSD Version 1.0 */
mmc_csd.card_cmd_class = UNPACK_BITS(raw_csd, 84, 12, mmc_sizeof);
@@ -177,7 +177,7 @@
/* Calculate the card capacity */
mmc_temp = (1 << (mmc_csd.c_size_mult + 2)) * (mmc_csd.c_size + 1);
- card->capacity = mmc_temp * mmc_csd.read_blk_len;
+ card->capacity = (unsigned long long)mmc_temp * mmc_csd.read_blk_len;
}
} else {
/* Parse CSD according to MMC card spec. */
@@ -213,7 +213,7 @@
if (mmc_csd.c_size != 0xFFF) {
/* For cards less than or equal to 2GB */
mmc_temp = (1 << (mmc_csd.c_size_mult + 2)) * (mmc_csd.c_size + 1);
- card->capacity = mmc_temp * mmc_csd.read_blk_len;
+ card->capacity = (unsigned long long) mmc_temp * mmc_csd.read_blk_len;
} else {
/* For cards greater than 2GB, Ext CSD register's SEC_COUNT
* is used to calculate the size.
@@ -224,7 +224,6 @@
| (card->ext_csd[MMC_SEC_COUNT3] << MMC_SEC_COUNT3_SHIFT)
| (card->ext_csd[MMC_SEC_COUNT2] << MMC_SEC_COUNT2_SHIFT)
| card->ext_csd[MMC_SEC_COUNT1];
-
card->capacity = sec_count * MMC_BLK_SZ;
}
}
@@ -234,22 +233,22 @@
sizeof(struct mmc_csd));
dprintf(SPEW, "Decoded CSD fields:\n");
- dprintf(SPEW, "cmmc_structure: %d\n", mmc_csd.cmmc_structure);
+ dprintf(SPEW, "cmmc_structure: %u\n", mmc_csd.cmmc_structure);
dprintf(SPEW, "card_cmd_class: %x\n", mmc_csd.card_cmd_class);
- dprintf(SPEW, "write_blk_len: %d\n", mmc_csd.write_blk_len);
- dprintf(SPEW, "read_blk_len: %d\n", mmc_csd.read_blk_len);
- dprintf(SPEW, "r2w_factor: %d\n", mmc_csd.r2w_factor);
- dprintf(SPEW, "sector_size: %d\n", mmc_csd.sector_size);
- dprintf(SPEW, "c_size_mult:%d\n", mmc_csd.c_size_mult);
- dprintf(SPEW, "c_size: %d\n", mmc_csd.c_size);
- dprintf(SPEW, "nsac_clk_cycle: %d\n", mmc_csd.nsac_clk_cycle);
- dprintf(SPEW, "taac_ns: %d\n", mmc_csd.taac_ns);
- dprintf(SPEW, "tran_speed: %d kbps\n", mmc_csd.tran_speed);
- dprintf(SPEW, "erase_blk_len: %d\n", mmc_csd.erase_blk_len);
- dprintf(SPEW, "read_blk_misalign: %d\n", mmc_csd.read_blk_misalign);
- dprintf(SPEW, "write_blk_misalign: %d\n", mmc_csd.write_blk_misalign);
- dprintf(SPEW, "read_blk_partial: %d\n", mmc_csd.read_blk_partial);
- dprintf(SPEW, "write_blk_partial: %d\n", mmc_csd.write_blk_partial);
+ dprintf(SPEW, "write_blk_len: %u\n", mmc_csd.write_blk_len);
+ dprintf(SPEW, "read_blk_len: %u\n", mmc_csd.read_blk_len);
+ dprintf(SPEW, "r2w_factor: %u\n", mmc_csd.r2w_factor);
+ dprintf(SPEW, "sector_size: %u\n", mmc_csd.sector_size);
+ dprintf(SPEW, "c_size_mult:%u\n", mmc_csd.c_size_mult);
+ dprintf(SPEW, "c_size: %u\n", mmc_csd.c_size);
+ dprintf(SPEW, "nsac_clk_cycle: %u\n", mmc_csd.nsac_clk_cycle);
+ dprintf(SPEW, "taac_ns: %u\n", mmc_csd.taac_ns);
+ dprintf(SPEW, "tran_speed: %u kbps\n", mmc_csd.tran_speed);
+ dprintf(SPEW, "erase_blk_len: %u\n", mmc_csd.erase_blk_len);
+ dprintf(SPEW, "read_blk_misalign: %u\n", mmc_csd.read_blk_misalign);
+ dprintf(SPEW, "write_blk_misalign: %u\n", mmc_csd.write_blk_misalign);
+ dprintf(SPEW, "read_blk_partial: %u\n", mmc_csd.read_blk_partial);
+ dprintf(SPEW, "write_blk_partial: %u\n", mmc_csd.write_blk_partial);
dprintf(SPEW, "Card Capacity: %llu Bytes\n", card->capacity);
return 0;
@@ -274,8 +273,7 @@
mmc_sizeof = sizeof(uint32_t) * 8;
- if ((card->type == MMC_TYPE_SDHC) ||
- (card->type == MMC_TYPE_STD_SD)) {
+ if (MMC_CARD_SD(card)) {
mmc_cid.mid = UNPACK_BITS(raw_cid, 120, 8, mmc_sizeof);
mmc_cid.oid = UNPACK_BITS(raw_cid, 104, 16, mmc_sizeof);
@@ -467,8 +465,7 @@
/* CMD3 Format:
* [31:0] stuff bits
*/
- if (card->type == MMC_TYPE_SDHC ||
- card->type == MMC_TYPE_STD_SD) {
+ if (MMC_CARD_SD(card)) {
cmd.cmd_index = CMD3_SEND_RELATIVE_ADDR;
cmd.argument = 0;
cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
@@ -535,14 +532,13 @@
/*
* Function: mmc select card
- * Arg : host, card structure & RCA
+ * Arg : host, card structure
* Return : 0 on Success, 1 on Failure
* Flow : Selects a card by sending CMD7 to the card with its RCA.
* If RCA field is set as 0 ( or any other address ),
* the card will be de-selected. (CMD7)
*/
-static uint32_t mmc_select_card(struct sdhci_host *host, struct mmc_card *card,
- uint32_t rca)
+static uint32_t mmc_select_card(struct sdhci_host *host, struct mmc_card *card)
{
struct mmc_command cmd;
uint32_t mmc_arg = 0;
@@ -554,16 +550,15 @@
* [31:16] RCA
* [15:0] stuff bits
*/
- mmc_arg |= rca << 16;
+ mmc_arg |= card->rca << 16;
cmd.cmd_index = CMD7_SELECT_DESELECT_CARD;
cmd.argument = mmc_arg;
cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
/* If we are deselecting card, we do not get response */
- if (rca == card->rca && rca) {
- if (card->type == MMC_TYPE_SDHC ||
- card->type == MMC_TYPE_STD_SD)
+ if (card->rca) {
+ if (MMC_CARD_SD(card))
cmd.resp_type = SDHCI_CMD_RESP_R1B;
else
cmd.resp_type = SDHCI_CMD_RESP_R1;
@@ -896,10 +891,27 @@
struct sdhci_host *host;
struct mmc_config_data *cfg;
+ struct sdhci_msm_data data;
+
+ event_t sdhc_event;
host = &dev->host;
cfg = &dev->config;
+ event_init(&sdhc_event, false, EVENT_FLAG_AUTOUNSIGNAL);
+
+ host->base = cfg->sdhc_base;
+ host->sdhc_event = &sdhc_event;
+
+ data.sdhc_event = &sdhc_event;
+ data.pwrctl_base = cfg->pwrctl_base;
+ data.pwr_irq = cfg->pwr_irq;
+
+ /*
+ * MSM specific sdhc init
+ */
+ sdhci_msm_init(&data);
+
/*
* Initialize the controller, read the host capabilities
* set power on mode
@@ -953,7 +965,7 @@
}
/* Select the card (CMD7) */
- mmc_return = mmc_select_card(host, card, card->rca);
+ mmc_return = mmc_select_card(host, card);
if (mmc_return) {
dprintf(CRITICAL, "Failure selecting the Card with RCA: %x\n",card->rca);
return mmc_return;
@@ -989,6 +1001,7 @@
* Send CMD1 to identify and reject cards that do not match host's VDD range
* profile. Cards sends its OCR register in response.
*/
+
mmc_return = mmc_send_op_cond(host, card);
/* OCR is not received, init could not complete */
@@ -1000,6 +1013,257 @@
return 0;
}
+static uint32_t mmc_send_app_cmd(struct sdhci_host *host, struct mmc_card *card)
+{
+ struct mmc_command cmd = {0};
+
+ cmd.cmd_index = CMD55_APP_CMD;
+ cmd.argument = (card->rca << 16);
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R1;
+
+ if (sdhci_send_command(host, &cmd))
+ {
+ dprintf(CRITICAL, "Failed Sending CMD55\n");
+ return 1;
+ }
+ return 0;
+}
+
+uint32_t mmc_sd_card_init(struct sdhci_host *host, struct mmc_card *card)
+{
+ uint8_t i;
+ uint32_t mmc_ret;
+ struct mmc_command cmd;
+
+ memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+ /* Use the SD card RCA 0x0 during init */
+ card->rca = SD_CARD_RCA;
+
+ /* Send CMD8 for voltage check*/
+ for (i = 0 ;i < SD_CMD8_MAX_RETRY; i++)
+ {
+ cmd.cmd_index = CMD8_SEND_IF_COND;
+ cmd.argument = MMC_SD_HC_VOLT_SUPPLIED;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R7;
+
+ if (sdhci_send_command(host, &cmd))
+ {
+ dprintf(CRITICAL, "The response for CMD8 does not match the supplied value\n");
+ return 1;
+ }
+ else
+ {
+ /* If the command response echos the voltage back */
+ if (cmd.resp[0] == MMC_SD_HC_VOLT_SUPPLIED)
+ break;
+ }
+ /* As per SDCC the spec try for max three times with
+ * 1 ms delay
+ */
+ mdelay(1);
+ }
+
+ if (i == SD_CMD8_MAX_RETRY && (cmd.resp[0] != MMC_SD_HC_VOLT_SUPPLIED))
+ {
+ dprintf(CRITICAL, "Error: CMD8 response timed out\n");
+ return 1;
+ }
+
+ /* Send ACMD41 for OCR */
+ for (i = 0; i < SD_ACMD41_MAX_RETRY; i++)
+ {
+ /* Send APP_CMD before ACMD41*/
+ if (mmc_send_app_cmd(host, card))
+ {
+ dprintf(CRITICAL, "Failed sending App command\n");
+ return 1;
+ }
+
+ /* APP_CMD is successful, send ACMD41 now */
+ cmd.cmd_index = ACMD41_SEND_OP_COND;
+ cmd.argument = MMC_SD_OCR | MMC_SD_HC_HCS;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R3;
+
+ if (sdhci_send_command(host, &cmd))
+ {
+ dprintf(CRITICAL, "Failure sending ACMD41\n");
+ return 1;
+ }
+ else
+ {
+ if (cmd.resp[0] & MMC_SD_DEV_READY)
+ {
+ if (cmd.resp[0] & (1 << 30))
+ card->type = MMC_CARD_TYPE_SDHC;
+ else
+ card->type = MMC_CARD_TYPE_STD_SD;
+
+ break;
+ }
+ }
+ /*
+ * As per SDCC spec try for max 1 second
+ */
+ mdelay(50);
+ }
+
+ if (i == SD_ACMD41_MAX_RETRY && !(cmd.resp[0] & MMC_SD_DEV_READY))
+ {
+ dprintf(CRITICAL, "Error: ACMD41 response timed out\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function to read SD card information from SD status
+ */
+static uint32_t mmc_sd_get_card_ssr(struct sdhci_host *host, struct mmc_card *card)
+{
+ BUF_DMA_ALIGN(raw_sd_status, 64);
+ struct mmc_command cmd = {0};
+ uint32_t sd_status[16];
+ uint32_t *status = sd_status;
+ uint32_t au_size;
+ int i;
+ int j;
+
+ if (mmc_send_app_cmd(host, card))
+ {
+ dprintf(CRITICAL, "Failed sending App command\n");
+ return 1;
+ }
+
+ cmd.cmd_index = ACMD13_SEND_SD_STATUS;
+ cmd.argument = 0x0;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R2;
+ cmd.trans_mode = SDHCI_MMC_READ;
+ cmd.data_present = 0x1;
+ cmd.data.data_ptr = raw_sd_status;
+ cmd.data.num_blocks = 0x1;
+ cmd.data.blk_sz = 0x40;
+
+ /* send command */
+ if (sdhci_send_command(host, &cmd))
+ return 1;
+
+ memcpy(sd_status, raw_sd_status, sizeof(sd_status));
+
+ for (i = 15, j = 0; i >=0 ; i--, j++)
+ sd_status[i] = swap_endian32(sd_status[j]);
+
+ au_size = UNPACK_BITS(status, MMC_SD_AU_SIZE_BIT, MMC_SD_AU_SIZE_LEN, 32);
+ /* Card AU size in sectors */
+ card->ssr.au_size = 1 << (au_size + 4);
+ card->ssr.num_aus = UNPACK_BITS(status, MMC_SD_ERASE_SIZE_BIT, MMC_SD_ERASE_SIZE_LEN, 32);
+
+ return 0;
+}
+
+/*
+ * Function to read the SD CARD configuration register
+ */
+static uint32_t mmc_sd_get_card_scr(struct sdhci_host *host, struct mmc_card *card)
+{
+ BUF_DMA_ALIGN(scr_resp, 8);
+ struct mmc_command cmd = {0};
+ uint32_t raw_scr[2];
+
+ /* Now read the SCR register */
+ /* Send APP_CMD before ACMD51*/
+ if (mmc_send_app_cmd(host, card))
+ {
+ dprintf(CRITICAL, "Failed sending App command\n");
+ return 1;
+ }
+
+ cmd.cmd_index = ACMD51_READ_CARD_SCR;
+ cmd.argument = 0x0;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R1;
+ cmd.trans_mode = SDHCI_MMC_READ;
+ cmd.data_present = 0x1;
+ cmd.data.data_ptr = scr_resp;
+ cmd.data.num_blocks = 0x1;
+ cmd.data.blk_sz = 0x8;
+
+ /* send command */
+ if (sdhci_send_command(host, &cmd))
+ return 1;
+
+ memcpy(raw_scr, scr_resp, sizeof(raw_scr));
+
+ card->raw_scr[0] = swap_endian32(raw_scr[0]);
+ card->raw_scr[1] = swap_endian32(raw_scr[1]);
+
+ /*
+ * Parse & Populate the SCR data as per sdcc spec
+ */
+ card->scr.bus_widths = (card->raw_scr[0] & SD_SCR_BUS_WIDTH_MASK) >> SD_SCR_BUS_WIDTH;
+ card->scr.cmd23_support = (card->raw_scr[0] & SD_SCR_CMD23_SUPPORT);
+ card->scr.sd_spec = (card->raw_scr[0] & SD_SCR_SD_SPEC_MASK) >> SD_SCR_SD_SPEC;
+ card->scr.sd3_spec = (card->raw_scr[0] & SD_SCR_SD_SPEC3_MASK) >> SD_SCR_SD_SPEC3;
+
+ return 0;
+}
+
+/*
+ * Function: mmc_set_sd_bus_width
+ * Arg : host, device structure & width
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Set the bus width for the card
+ */
+uint32_t mmc_sd_set_bus_width(struct sdhci_host *host, struct mmc_card *card, uint8_t width)
+{
+ struct mmc_command cmd = {0};
+
+ /* Send APP_CMD before ACMD6*/
+ if (mmc_send_app_cmd(host, card))
+ {
+ dprintf(CRITICAL, "Failed sending App command\n");
+ return 1;
+ }
+
+ cmd.cmd_index = ACMD6_SET_BUS_WIDTH;
+ cmd.argument = (width == DATA_BUS_WIDTH_4BIT) ? (1<<1) : 0;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R1;
+
+ /* send command */
+ if (sdhci_send_command(host, &cmd))
+ return 1;
+
+ return 0;
+}
+
+uint32_t mmc_sd_set_hs(struct sdhci_host *host, struct mmc_card *card)
+{
+ struct mmc_command cmd = {0};
+ BUF_DMA_ALIGN(switch_resp, 64);
+
+ cmd.cmd_index = CMD6_SWITCH_FUNC;
+ cmd.argument = MMC_SD_SWITCH_HS;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R1;
+ cmd.trans_mode = SDHCI_MMC_READ;
+ cmd.data_present = 0x1;
+ cmd.data.data_ptr = switch_resp;
+ cmd.data.num_blocks = 0x1;
+ cmd.data.blk_sz = 0x40;
+
+ /* send command */
+ if (sdhci_send_command(host, &cmd))
+ return 1;
+
+ return 0;
+}
+
/*
* Function: mmc_init_card
* Arg : mmc device structure
@@ -1028,10 +1292,19 @@
/* TODO: Get the OCR params from target */
card->ocr = MMC_OCR_27_36 | MMC_OCR_SEC_MODE;
- /* Reset the card & get the OCR */
+ /* Initialize the internal MMC */
mmc_return = mmc_reset_card_and_send_op(host, card);
if (mmc_return)
- return mmc_return;
+ {
+ dprintf(CRITICAL, "MMC card failed to respond, try for SD card\n");
+ /* Reset the card & get the OCR */
+ mmc_return = mmc_sd_card_init(host, card);
+ if (mmc_return)
+ {
+ dprintf(CRITICAL, "Failed to initialize SD card\n");
+ return mmc_return;
+ }
+ }
/* Identify (CMD2, CMD3 & CMD9) and select the card (CMD7) */
mmc_return = mmc_identify_card(host, card);
@@ -1039,18 +1312,30 @@
return mmc_return;
/* set interface speed */
- mmc_return = mmc_set_hs_interface(host, card);
- if (mmc_return) {
- dprintf(CRITICAL, "Error adjusting interface speed!\n");
- return mmc_return;
+ if (MMC_CARD_SD(card))
+ {
+ mmc_return = mmc_sd_set_hs(host, card);
+ if (mmc_return)
+ {
+ dprintf(CRITICAL, "Failed to set HS for SD card\n");
+ return mmc_return;
+ }
+ }
+ else
+ {
+ mmc_return = mmc_set_hs_interface(host, card);
+ if (mmc_return) {
+ dprintf(CRITICAL, "Error adjusting interface speed!\n");
+ return mmc_return;
+ }
}
/* Set the sdcc clock to 50 MHZ */
sdhci_clk_supply(host, SDHCI_CLK_50MHZ);
/* Now get the extended CSD for the card */
- if ((card->type == MMC_TYPE_STD_MMC) ||
- (card->type == MMC_TYPE_MMCHC)) {
+ if (MMC_CARD_MMC(card))
+ {
/* For MMC cards, also get the extended csd */
mmc_return = mmc_get_ext_csd(host, card);
@@ -1059,6 +1344,21 @@
return mmc_return;
}
}
+ else
+ {
+ /*Read SCR for sd card */
+ if (mmc_sd_get_card_scr(host, card))
+ {
+ dprintf(CRITICAL, "Failure getting card's SCR register\n");
+ return 1;
+ }
+ /* Read SSR for the SD card */
+ if (mmc_sd_get_card_ssr(host, card))
+ {
+ dprintf(CRITICAL, "Failed to get SSR from the card\n");
+ return 1;
+ }
+ }
/* Decode and save the CSD register */
mmc_return = mmc_decode_and_save_csd(card);
@@ -1068,53 +1368,79 @@
}
- /* Set the bus width based on host, target capbilities */
- if (cfg->bus_width == DATA_BUS_WIDTH_8BIT && host->caps.bus_width_8bit)
- bus_width = DATA_BUS_WIDTH_8BIT;
- /*
- * Host contoller by default supports 4 bit & 1 bit mode.
- * No need to check for host support here
- */
- else if (cfg->bus_width == DATA_BUS_WIDTH_4BIT)
- bus_width = DATA_BUS_WIDTH_4BIT;
+ if (MMC_CARD_MMC(card))
+ {
+ /* Set the bus width based on host, target capbilities */
+ if (cfg->bus_width == DATA_BUS_WIDTH_8BIT && host->caps.bus_width_8bit)
+ bus_width = DATA_BUS_WIDTH_8BIT;
+ /*
+ * Host contoller by default supports 4 bit & 1 bit mode.
+ * No need to check for host support here
+ */
+ else if (cfg->bus_width == DATA_BUS_WIDTH_4BIT)
+ bus_width = DATA_BUS_WIDTH_4BIT;
+ else
+ bus_width = DATA_BUS_WIDTH_1BIT;
+
+ /* Set 4/8 bit SDR bus width in controller */
+ mmc_return = sdhci_set_bus_width(host, bus_width);
+
+ if (mmc_return) {
+ dprintf(CRITICAL, "Failed to set bus width for host controller\n");
+ return 1;
+ }
+
+ /* Enable high speed mode in the follwing order:
+ * 1. HS200 mode if supported by host & card
+ * 2. DDR mode host, if supported by host & card
+ * 3. Use normal speed mode with supported bus width
+ */
+ if (mmc_card_supports_hs200_mode(card) && host->caps.sdr50_support) {
+ mmc_return = mmc_set_hs200_mode(host, card, bus_width);
+
+ if (mmc_return) {
+ dprintf(CRITICAL, "Failure to set HS200 mode for Card(RCA:%x)\n",
+ card->rca);
+ return mmc_return;
+ }
+ } else if (mmc_card_supports_ddr_mode(card) && host->caps.ddr_support) {
+ mmc_return = mmc_set_ddr_mode(host, card);
+
+ if (mmc_return) {
+ dprintf(CRITICAL, "Failure to set DDR mode for Card(RCA:%x)\n",
+ card->rca);
+ return mmc_return;
+ }
+ } else {
+ /* Set 4/8 bit bus width for the card */
+ mmc_return = mmc_set_bus_width(host, card, bus_width);
+ if (mmc_return) {
+ dprintf(CRITICAL, "Failure to set wide bus for Card(RCA:%x)\n",
+ card->rca);
+ return mmc_return;
+ }
+ }
+ }
else
+ {
+ /* Check the supported bus width for the card from SCR register */
+ if (card->scr.bus_widths & SD_SCR_WIDTH_4BIT)
+ bus_width = DATA_BUS_WIDTH_4BIT;
+ else
bus_width = DATA_BUS_WIDTH_1BIT;
- /* Set 4/8 bit SDR bus width in controller */
- mmc_return = sdhci_set_bus_width(host, bus_width);
-
- if (mmc_return) {
- dprintf(CRITICAL, "Failed to set bus width for host controller\n");
- return 1;
- }
-
- /* Enable high speed mode in the follwing order:
- * 1. HS200 mode if supported by host & card
- * 2. DDR mode host, if supported by host & card
- * 3. Use normal speed mode with supported bus width
- */
- if (mmc_card_supports_hs200_mode(card) && host->caps.sdr50_support) {
- mmc_return = mmc_set_hs200_mode(host, card, bus_width);
-
- if (mmc_return) {
- dprintf(CRITICAL, "Failure to set HS200 mode for Card(RCA:%x)\n",
- card->rca);
+ mmc_return = mmc_sd_set_bus_width(host, card, bus_width);
+ if (mmc_return)
+ {
+ dprintf(CRITICAL, "Failed to set bus width for the card\n");
return mmc_return;
}
- } else if (mmc_card_supports_ddr_mode(card) && host->caps.ddr_support) {
- mmc_return = mmc_set_ddr_mode(host, card);
- if (mmc_return) {
- dprintf(CRITICAL, "Failure to set DDR mode for Card(RCA:%x)\n",
- card->rca);
- return mmc_return;
- }
- } else {
- /* Set 4/8 bit bus width for the card */
- mmc_return = mmc_set_bus_width(host, card, bus_width);
- if (mmc_return) {
- dprintf(CRITICAL, "Failure to set wide bus for Card(RCA:%x)\n",
- card->rca);
+ /* Set bit SDR bus width in controller */
+ mmc_return = sdhci_set_bus_width(host, bus_width);
+ if (mmc_return)
+ {
+ dprintf(CRITICAL, "Failed to set bus width for host controller\n");
return mmc_return;
}
}
@@ -1174,8 +1500,6 @@
memset((struct mmc_card *)&dev->card, 0, sizeof(struct mmc_card));
- dev->host.base = data->base;
-
/* Initialize the host & clock */
dprintf(SPEW, " Initializing MMC host data structure and clock!\n");
@@ -1227,6 +1551,8 @@
cmd.resp_type = SDHCI_CMD_RESP_R1;
cmd.trans_mode = SDHCI_MMC_READ;
cmd.data_present = 0x1;
+ /* Use CMD23 If card supports cMD23 */
+ cmd.cmd23_support = dev->card.scr.cmd23_support;
cmd.data.data_ptr = dest;
cmd.data.num_blocks = num_blocks;
@@ -1284,6 +1610,8 @@
cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
cmd.resp_type = SDHCI_CMD_RESP_R1;
cmd.trans_mode = SDHCI_MMC_WRITE;
+ /* Use CMD23 If card supports cMD23 */
+ cmd.cmd23_support = dev->card.scr.cmd23_support;
cmd.data_present = 0x1;
cmd.data.data_ptr = src;
cmd.data.num_blocks = num_blocks;
@@ -1320,10 +1648,15 @@
static uint32_t mmc_send_erase_grp_start(struct mmc_device *dev, uint32_t erase_start)
{
struct mmc_command cmd;
+ struct mmc_card *card = &dev->card;
memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
- cmd.cmd_index = CMD35_ERASE_GROUP_START;
+ if (MMC_CARD_MMC(card))
+ cmd.cmd_index = CMD35_ERASE_GROUP_START;
+ else
+ cmd.cmd_index = CMD32_ERASE_WR_BLK_START;
+
cmd.argument = erase_start;
cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
cmd.resp_type = SDHCI_CMD_RESP_R1;
@@ -1350,10 +1683,15 @@
static uint32_t mmc_send_erase_grp_end(struct mmc_device *dev, uint32_t erase_end)
{
struct mmc_command cmd;
+ struct mmc_card *card = &dev->card;
memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
- cmd.cmd_index = CMD36_ERASE_GROUP_END;
+ if (MMC_CARD_MMC(card))
+ cmd.cmd_index = CMD36_ERASE_GROUP_END;
+ else
+ cmd.cmd_index = CMD33_ERASE_WR_BLK_END;
+
cmd.argument = erase_end;
cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
cmd.resp_type = SDHCI_CMD_RESP_R1;
@@ -1433,14 +1771,29 @@
uint32_t blk_end;
uint32_t num_erase_grps;
uint32_t *out;
+ struct mmc_card *card;
+
+
+ card = &dev->card;
/*
- * Calculate the erase unit size as per the emmc specification v4.5
+ * Calculate the erase unit size,
+ * 1. Based on emmc 4.5 spec for emmc card
+ * 2. Use SD Card Status info for SD cards
*/
- if (dev->card.ext_csd[MMC_ERASE_GRP_DEF])
- erase_unit_sz = (MMC_HC_ERASE_MULT * dev->card.ext_csd[MMC_HC_ERASE_GRP_SIZE]) / MMC_BLK_SZ;
+ if (MMC_CARD_MMC(card))
+ {
+ /*
+ * Calculate the erase unit size as per the emmc specification v4.5
+ */
+ if (dev->card.ext_csd[MMC_ERASE_GRP_DEF])
+ erase_unit_sz = (MMC_HC_ERASE_MULT * dev->card.ext_csd[MMC_HC_ERASE_GRP_SIZE]) / MMC_BLK_SZ;
+ else
+ erase_unit_sz = (dev->card.csd.erase_grp_size + 1) * (dev->card.csd.erase_grp_mult + 1);
+ }
else
- erase_unit_sz = (dev->card.csd.erase_grp_size + 1) * (dev->card.csd.erase_grp_mult + 1);
+ erase_unit_sz = dev->card.ssr.au_size * dev->card.ssr.num_aus;
+
/* Convert length in blocks */
len = len / MMC_BLK_SZ;
diff --git a/platform/msm_shared/qtimer.c b/platform/msm_shared/qtimer.c
index bf9de81..c8d6bd7 100644
--- a/platform/msm_shared/qtimer.c
+++ b/platform/msm_shared/qtimer.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -93,7 +93,7 @@
{
uint64_t ticks;
- ticks = (msecs * ticks_per_sec) / 1000;
+ ticks = ((uint64_t) msecs * ticks_per_sec) / 1000;
delay(ticks);
}
@@ -102,7 +102,7 @@
{
uint64_t ticks;
- ticks = (usecs * ticks_per_sec) / 1000000;
+ ticks = ((uint64_t) usecs * ticks_per_sec) / 1000000;
delay(ticks);
}
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index 72982b1..1fec96b 100755
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -19,6 +19,7 @@
ifeq ($(ENABLE_SDHCI_SUPPORT),1)
OBJS += \
$(LOCAL_DIR)/sdhci.o \
+ $(LOCAL_DIR)/sdhci_msm.o \
$(LOCAL_DIR)/mmc_sdhci.o \
$(LOCAL_DIR)/mmc_wrapper.o
else
diff --git a/platform/msm_shared/sdhci.c b/platform/msm_shared/sdhci.c
index 417e0eb..ce54433 100644
--- a/platform/msm_shared/sdhci.c
+++ b/platform/msm_shared/sdhci.c
@@ -40,41 +40,6 @@
/*
- * Function: sdhci int handler
- * Arg : Event argument
- * Return : 0
- * Flow: : 1. Read the power control mask register
- * 2. Check if bus is ON
- * 3. Write success to ack regiser
- * Details : This is power control interrupt handler.
- * Once we receive the interrupt, we will ack the power control
- * register that we have successfully completed pmic transactions
- */
-enum handler_return sdhci_int_handler(void *arg)
-{
- uint32_t ack;
- uint32_t status;
-
- /*
- * Read the mask register to check if BUS & IO level
- * interrupts are enabled
- */
- status = readl(SDCC_HC_PWRCTL_MASK_REG);
-
- if (status & (SDCC_HC_BUS_ON | SDCC_HC_BUS_OFF))
- ack = SDCC_HC_BUS_ON_OFF_SUCC;
- if (status & (SDCC_HC_IO_SIG_LOW | SDCC_HC_IO_SIG_HIGH))
- ack |= SDCC_HC_IO_SIG_SUCC;
-
- /* Write success to power control register */
- writel(ack, SDCC_HC_PWRCTL_CTL_REG);
-
- event_signal((event_t *)arg, false);
-
- return 0;
-}
-
-/*
* Function: sdhci error status enable
* Arg : Host structure
* Return : None
@@ -207,7 +172,7 @@
voltage = host->caps.voltage;
voltage <<= SDHCI_BUS_VOL_SEL;
- REG_WRITE8(host, voltage, SDHCI_BUS_PWR_EN);
+ REG_WRITE8(host, voltage, SDHCI_PWR_CTRL_REG);
voltage |= SDHCI_BUS_PWR_EN;
@@ -458,6 +423,8 @@
if (int_status & SDHCI_ERR_INT_STAT_MASK) {
if (sdhci_cmd_err_status(host)) {
dprintf(CRITICAL, "Error: Command completed with errors\n");
+ /* Reset the command & Data line */
+ REG_WRITE8(host, (SOFT_RESET_CMD | SOFT_RESET_DATA), SDHCI_RESET_REG);
return 1;
}
}
@@ -712,10 +679,16 @@
if (cmd->trans_mode == SDHCI_MMC_READ)
trans_mode |= SDHCI_READ_MODE;
- /* Enable auto cmd 23 for multi block transfer */
+ /* Enable auto cmd23 or cmd12 for multi block transfer
+ * based on what command card supports
+ */
if (cmd->data.num_blocks > 1) {
- trans_mode |= SDHCI_TRANS_MULTI | SDHCI_AUTO_CMD23_EN | SDHCI_BLK_CNT_EN;
- REG_WRITE32(host, cmd->data.num_blocks, SDHCI_ARG2_REG);
+ 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);
+ }
+ else
+ trans_mode |= SDHCI_TRANS_MULTI | SDHCI_AUTO_CMD12_EN | SDHCI_BLK_CNT_EN;
}
}
@@ -763,20 +736,6 @@
}
/*
- * Function: sdhci mode enable
- * Arg : Flag (0/1)
- * Return : None
- * Flow: : Enable/Disable Sdhci mode
- */
-void sdhci_mode_enable(uint8_t enable)
-{
- if (enable)
- writel(SDHCI_HC_MODE_EN, SDCC_MCI_HC_MODE);
- else
- writel(SDHCI_HC_MODE_DIS, SDCC_MCI_HC_MODE);
-}
-
-/*
* Function: sdhci init
* Arg : Host structure
* Return : None
@@ -791,9 +750,6 @@
void sdhci_init(struct sdhci_host *host)
{
uint32_t caps[2];
- event_t sdhc_event;
-
- event_init(&sdhc_event, false, EVENT_FLAG_AUTOUNSIGNAL);
/*
* Reset the controller
@@ -832,20 +788,11 @@
/* SDR50 mode support */
host->caps.sdr50_support = (caps[1] & SDHCI_SDR50_MODE_MASK) ? 1 : 0;
- /*
- * Register the interrupt handler for pwr irq
- */
- register_int_handler(SDCC_PWRCTRL_IRQ, sdhci_int_handler, &sdhc_event);
- unmask_interrupt(SDCC_PWRCTRL_IRQ);
-
- /* Enable pwr control interrupt */
- writel(SDCC_HC_PWR_CTRL_INT, SDCC_HC_PWRCTL_MASK_REG);
-
/* Set bus power on */
sdhci_set_bus_power_on(host);
/* Wait for power interrupt to be handled */
- event_wait(&sdhc_event);
+ event_wait(host->sdhc_event);
/* Set bus width */
sdhci_set_bus_width(host, SDHCI_BUS_WITDH_1BIT);
diff --git a/platform/msm_shared/sdhci_msm.c b/platform/msm_shared/sdhci_msm.c
new file mode 100644
index 0000000..1b6c8b0
--- /dev/null
+++ b/platform/msm_shared/sdhci_msm.c
@@ -0,0 +1,139 @@
+/* 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 <platform/iomap.h>
+#include <platform/irqs.h>
+#include <platform/interrupts.h>
+#include <platform/timer.h>
+#include <target.h>
+#include <string.h>
+#include <stdlib.h>
+#include <bits.h>
+#include <debug.h>
+#include <sdhci.h>
+#include <sdhci_msm.h>
+
+
+/*
+ * Function: sdhci int handler
+ * Arg : MSM specific data for sdhci
+ * Return : 0
+ * Flow: : 1. Read the power control mask register
+ * 2. Check if bus is ON
+ * 3. Write success to ack regiser
+ * Details : This is power control interrupt handler.
+ * Once we receive the interrupt, we will ack the power control
+ * register that we have successfully completed pmic transactions
+ */
+static enum handler_return sdhci_int_handler(struct sdhci_msm_data *data)
+{
+ uint32_t ack;
+ uint32_t status;
+
+ /*
+ * Read the mask register to check if BUS & IO level
+ * interrupts are enabled
+ */
+ status = readl(data->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG);
+
+ if (status & (SDCC_HC_BUS_ON | SDCC_HC_BUS_OFF))
+ ack = SDCC_HC_BUS_ON_OFF_SUCC;
+ if (status & (SDCC_HC_IO_SIG_LOW | SDCC_HC_IO_SIG_HIGH))
+ ack |= SDCC_HC_IO_SIG_SUCC;
+
+ /* Write success to power control register */
+ writel(ack, (data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG));
+
+ event_signal(data->sdhc_event, false);
+
+ return 0;
+}
+
+/*
+ * Function: sdhci clear pending interrupts
+ * Arg : MSM specific data for sdhci
+ * Return : None
+ * Flow: : Clear pending interrupts
+ */
+static void sdhci_clear_power_ctrl_irq(struct sdhci_msm_data *data)
+{
+ uint32_t irq_ctl;
+ uint32_t irq_stat;
+
+ /*
+ * Read the power control status register to know
+ * the status of BUS & IO_HIGH_V
+ */
+ irq_stat = readl(data->pwrctl_base + SDCC_HC_PWRCTL_STATUS_REG);
+
+ /* Clear the power control status */
+ writel(irq_stat, (data->pwrctl_base + SDCC_HC_PWRCTL_CLEAR_REG));
+
+ /*
+ * Handle the pending irq by ack'ing the bus & IO switch
+ */
+ irq_ctl = readl(data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG);
+
+ if (irq_stat & (SDCC_HC_BUS_ON | SDCC_HC_BUS_OFF))
+ irq_ctl |= SDCC_HC_BUS_ON_OFF_SUCC;
+ if (irq_stat & (SDCC_HC_IO_SIG_LOW | SDCC_HC_IO_SIG_HIGH))
+ irq_ctl |= SDCC_HC_IO_SIG_SUCC;
+
+ writel(irq_ctl, (data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG));
+}
+
+/*
+ * Function: sdhci msm init
+ * Arg : MSM specific config data for sdhci
+ * Return : None
+ * Flow: : Enable sdhci mode & do msm specific init
+ */
+void sdhci_msm_init(struct sdhci_msm_data *config)
+{
+ /* Enable sdhc mode */
+ writel(SDHCI_HC_MODE_EN, (config->pwrctl_base + SDCC_MCI_HC_MODE));
+
+ /*
+ * CORE_SW_RST may trigger power irq if previous status of PWRCTL
+ * was either BUS_ON or IO_HIGH. So before we enable the power irq
+ * interrupt in GIC (by registering the interrupt handler), we need to
+ * ensure that any pending power irq interrupt status is acknowledged
+ * otherwise power irq interrupt handler would be fired prematurely.
+ */
+ sdhci_clear_power_ctrl_irq(config);
+
+ /*
+ * Register the interrupt handler for pwr irq
+ */
+ register_int_handler(config->pwr_irq, sdhci_int_handler, (void *)config);
+
+ unmask_interrupt(config->pwr_irq);
+
+ /* Enable pwr control interrupt */
+ writel(SDCC_HC_PWR_CTRL_INT, (config->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG));
+}
diff --git a/platform/msm_shared/smem.h b/platform/msm_shared/smem.h
index 3782c12..8ebbce8 100755
--- a/platform/msm_shared/smem.h
+++ b/platform/msm_shared/smem.h
@@ -342,6 +342,7 @@
enum platform_subtype {
HW_PLATFORM_SUBTYPE_UNKNOWN = 0,
HW_PLATFORM_SUBTYPE_MDM = 1,
+ HW_PLATFORM_SUBTYPE_8974PRO_PM8084 = 1,
HW_PLATFORM_SUBTYPE_CSFB = 1,
HW_PLATFORM_SUBTYPE_SVLTE1 = 2,
HW_PLATFORM_SUBTYPE_SVLTE2A = 3,
diff --git a/target/msm8226/init.c b/target/msm8226/init.c
index d8c7031..3dcdbd5 100644
--- a/target/msm8226/init.c
+++ b/target/msm8226/init.c
@@ -28,6 +28,7 @@
#include <debug.h>
#include <platform/iomap.h>
+#include <platform/irqs.h>
#include <reg.h>
#include <target.h>
#include <platform.h>
@@ -67,9 +68,15 @@
HW_PLATFORM_SUBTYPE_SKUAB = 3,
};
+static uint32_t mmc_pwrctl_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 };
+static uint32_t mmc_sdc_pwrctl_irq[] =
+ { SDCC1_PWRCTL_IRQ, SDCC2_PWRCTL_IRQ, SDCC3_PWRCTL_IRQ };
+
struct mmc_device *dev;
void target_early_init(void)
@@ -140,27 +147,30 @@
void target_sdc_init()
{
- struct mmc_config_data config;
+ struct mmc_config_data config = {0};
/*
* 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];
+ 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];
+
if (!(dev = mmc_init(&config)))
{
/* Trying Slot 2 next */
config.slot = 2;
- config.base = mmc_sdhci_base[config.slot - 1];
+ 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];
+
if (!(dev = mmc_init(&config))) {
dprintf(CRITICAL, "mmc init failed!");
ASSERT(0);
diff --git a/target/msm8974/init.c b/target/msm8974/init.c
index 683bf5c..b5fbf82 100644
--- a/target/msm8974/init.c
+++ b/target/msm8974/init.c
@@ -80,6 +80,8 @@
#define SSD_PARTITION_SIZE 8192
#endif
+#define FASTBOOT_MODE 0x77665500
+
#define BOARD_SOC_VERSION1(soc_rev) (soc_rev >= 0x10000 && soc_rev < 0x20000)
#if MMC_SDHCI_SUPPORT
@@ -427,10 +429,8 @@
*/
switch(platform_subtype) {
case HW_PLATFORM_SUBTYPE_UNKNOWN:
+ case HW_PLATFORM_SUBTYPE_8974PRO_PM8084:
break;
- case HW_PLATFORM_SUBTYPE_MDM:
- board->baseband = BASEBAND_MDM;
- return;
default:
dprintf(CRITICAL, "Platform Subtype : %u is not supported\n",platform_subtype);
ASSERT(0);
@@ -500,6 +500,7 @@
void reboot_device(unsigned reboot_reason)
{
uint32_t soc_ver = 0;
+ uint8_t reset_type = 0;
soc_ver = board_soc_version();
@@ -509,11 +510,16 @@
else
writel(reboot_reason, RESTART_REASON_ADDR_V2);
+ if(reboot_reason == FASTBOOT_MODE)
+ reset_type = PON_PSHOLD_WARM_RESET;
+ else
+ reset_type = PON_PSHOLD_HARD_RESET;
+
/* Configure PMIC for warm reset */
if (target_is_8974() && (pmic_ver == PM8X41_VERSION_V2))
- pm8x41_v2_reset_configure(PON_PSHOLD_WARM_RESET);
+ pm8x41_v2_reset_configure(reset_type);
else
- pm8x41_reset_configure(PON_PSHOLD_WARM_RESET);
+ pm8x41_reset_configure(reset_type);
/* Disable Watchdog Debug.
* Required becuase of a H/W bug which causes the system to