sdhci: sdhci-msm: update dll configuration

The newer msm sdhci's cores use a different DLL hardware for HS400.
Update the configuration and calibration of the newer DLL block.

The HS400 DLL block used previously is CDC LP 533 and requires
programming multiple registers and waiting for configuration to
complete and then enable it. It has about 18 register writes and
two register reads.

The newer HS400 DLL block is SDC4 DLL and requires two register
writes for configuration and one register read to confirm that it
is initialized. There is an additional register write to enable
the power save mode for SDC4 DLL block.

Change-Id: I20ddeaee9309c43cd51bebdfc02d70553c9d2a87
Signed-off-by: Krishna Konda <kkonda@codeaurora.org>
This commit is contained in:
Krishna Konda 2014-06-04 01:25:16 -07:00 committed by Subhash Jadavani
parent 87baaf7467
commit 7302266f4c

View file

@ -80,6 +80,7 @@
#define CORE_DLL_STATUS 0x108 #define CORE_DLL_STATUS 0x108
#define CORE_DLL_LOCK (1 << 7) #define CORE_DLL_LOCK (1 << 7)
#define CORE_DDR_DLL_LOCK (1 << 11)
#define CORE_VENDOR_SPEC 0x10C #define CORE_VENDOR_SPEC 0x10C
#define CORE_CLK_PWRSAVE (1 << 1) #define CORE_CLK_PWRSAVE (1 << 1)
@ -128,6 +129,15 @@
#define CORE_DDR_200_CFG 0x184 #define CORE_DDR_200_CFG 0x184
#define CORE_CDC_T4_DLY_SEL (1 << 0) #define CORE_CDC_T4_DLY_SEL (1 << 0)
#define CORE_START_CDC_TRAFFIC (1 << 6) #define CORE_START_CDC_TRAFFIC (1 << 6)
#define CORE_VENDOR_SPEC3 0x1B0
#define CORE_PWRSAVE_DLL (1 << 3)
#define CORE_DLL_CONFIG_2 0x1B4
#define CORE_DDR_CAL_EN (1 << 0)
#define CORE_DDR_CONFIG 0x1B8
#define DDR_CONFIG_POR_VAL 0x80040853
#define CORE_MCI_DATA_CNT 0x30 #define CORE_MCI_DATA_CNT 0x30
#define CORE_MCI_STATUS 0x34 #define CORE_MCI_STATUS 0x34
@ -291,6 +301,7 @@ struct sdhci_msm_host {
bool en_auto_cmd21; bool en_auto_cmd21;
struct device_attribute auto_cmd21_attr; struct device_attribute auto_cmd21_attr;
atomic_t controller_clock; atomic_t controller_clock;
bool use_cdclp533;
}; };
enum vdd_io_level { enum vdd_io_level {
@ -705,32 +716,12 @@ out:
static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host) static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
{ {
u32 wait_cnt; u32 calib_done;
int ret = 0; int ret = 0;
int cdc_err = 0; int cdc_err = 0;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__); pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__);
/*
* Retuning in HS400 (DDR mode) will fail, just reset the
* tuning block and restore the saved tuning phase.
*/
ret = msm_init_cm_dll(host);
if (ret)
goto out;
/* Set the selected phase in delay line hw block */
ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
if (ret)
goto out;
/* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
| CORE_CMD_DAT_TRACK_SEL),
host->ioaddr + CORE_DLL_CONFIG);
/* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */ /* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */
writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG) writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG)
& ~CORE_CDC_T4_DLY_SEL), & ~CORE_CDC_T4_DLY_SEL),
@ -800,18 +791,13 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
mb(); mb();
/* Poll on CALIBRATION_DONE field in CORE_CSR_CDC_STATUS0 to be 1 */ /* Poll on CALIBRATION_DONE field in CORE_CSR_CDC_STATUS0 to be 1 */
wait_cnt = 50; ret = readl_poll_timeout(host->ioaddr + CORE_CSR_CDC_STATUS0,
while (!(readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0) calib_done, (calib_done & CORE_CALIBRATION_DONE), 1, 50);
& CORE_CALIBRATION_DONE)) {
/* max. wait for 50us sec for CALIBRATION_DONE bit to be set */ if (ret == -ETIMEDOUT) {
if (--wait_cnt == 0) { pr_err("%s: %s: CDC Calibration was not completed\n",
pr_err("%s: %s: CDC Calibration was not completed\n",
mmc_hostname(host->mmc), __func__); mmc_hostname(host->mmc), __func__);
ret = -ETIMEDOUT; goto out;
goto out;
}
/* wait for 1us before polling again */
udelay(1);
} }
/* Verify CDC_ERROR_CODE field in CORE_CSR_CDC_STATUS0 is 0 */ /* Verify CDC_ERROR_CODE field in CORE_CSR_CDC_STATUS0 is 0 */
@ -834,6 +820,81 @@ out:
return ret; return ret;
} }
static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
{
u32 dll_status;
int ret = 0;
pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__);
/*
* Currently the CORE_DDR_CONFIG register defaults to desired
* configuration on reset. Currently reprogramming the power on
* reset (POR) value in case it might have been modified by
* bootloaders. In the future, if this changes, then the desired
* values will need to be programmed appropriately.
*/
writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + CORE_DDR_CONFIG);
/* Write 1 to DDR_CAL_EN field in CORE_DLL_CONFIG_2 */
writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
| CORE_DDR_CAL_EN),
host->ioaddr + CORE_DLL_CONFIG_2);
/* Poll on DDR_DLL_LOCK bit in CORE_DLL_STATUS to be set */
ret = readl_poll_timeout(host->ioaddr + CORE_DLL_STATUS,
dll_status, (dll_status & CORE_DDR_DLL_LOCK), 10, 1000);
if (ret == -ETIMEDOUT) {
pr_err("%s: %s: CM_DLL_SDC4 Calibration was not completed\n",
mmc_hostname(host->mmc), __func__);
goto out;
}
/* set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3 */
writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC3)
| CORE_PWRSAVE_DLL),
host->ioaddr + CORE_VENDOR_SPEC3);
mb();
out:
pr_debug("%s: Exit %s, ret:%d\n", mmc_hostname(host->mmc),
__func__, ret);
return ret;
}
static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
{
int ret = 0;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__);
/*
* Retuning in HS400 (DDR mode) will fail, just reset the
* tuning block and restore the saved tuning phase.
*/
ret = msm_init_cm_dll(host);
if (ret)
goto out;
/* Set the selected phase in delay line hw block */
ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
if (ret)
goto out;
if (msm_host->use_cdclp533)
/* Calibrate CDCLP533 DLL HW */
ret = sdhci_msm_cdclp533_calibration(host);
else
/* Calibrate CM_DLL_SDC4 HW */
ret = sdhci_msm_cm_dll_sdc4_calibration(host);
out:
pr_debug("%s: Exit %s, ret:%d\n", mmc_hostname(host->mmc),
__func__, ret);
return ret;
}
static void sdhci_msm_set_mmc_drv_type(struct sdhci_host *host, u32 opcode, static void sdhci_msm_set_mmc_drv_type(struct sdhci_host *host, u32 opcode,
u8 drv_type) u8 drv_type)
{ {
@ -891,10 +952,10 @@ int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__); pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
/* CDCLP533 HW calibration is only required for HS400 mode*/ /* CDC/SDC4 DLL HW calibration is only required for HS400 mode*/
if (msm_host->tuning_done && !msm_host->calibration_done && if (msm_host->tuning_done && !msm_host->calibration_done &&
(mmc->ios.timing == MMC_TIMING_MMC_HS400)) { (mmc->ios.timing == MMC_TIMING_MMC_HS400)) {
rc = sdhci_msm_cdclp533_calibration(host); rc = sdhci_msm_hs400_dll_calibration(host);
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
if (!rc) if (!rc)
msm_host->calibration_done = true; msm_host->calibration_done = true;
@ -2378,7 +2439,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv; struct sdhci_msm_host *msm_host = pltfm_host->priv;
struct mmc_ios curr_ios = host->mmc->ios; struct mmc_ios curr_ios = host->mmc->ios;
u32 sup_clock, ddr_clock; u32 sup_clock, ddr_clock, dll_lock;
bool curr_pwrsave; bool curr_pwrsave;
if (!clock) { if (!clock) {
@ -2465,7 +2526,27 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
| CORE_HC_SELECT_IN_EN), | CORE_HC_SELECT_IN_EN),
host->ioaddr + CORE_VENDOR_SPEC); host->ioaddr + CORE_VENDOR_SPEC);
} }
if (!host->mmc->ios.old_rate && !msm_host->use_cdclp533) {
/*
* Poll on DLL_LOCK and DDR_DLL_LOCK bits in
* CORE_DLL_STATUS to be set. This should get set
* with in 15 us at 200 MHz.
*/
rc = readl_poll_timeout(host->ioaddr + CORE_DLL_STATUS,
dll_lock, (dll_lock & (CORE_DLL_LOCK |
CORE_DDR_DLL_LOCK)), 10, 1000);
if (rc == -ETIMEDOUT)
pr_err("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n",
mmc_hostname(host->mmc),
dll_lock);
}
} else { } else {
if (!msm_host->use_cdclp533)
/* set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3 */
writel_relaxed((readl_relaxed(host->ioaddr +
CORE_VENDOR_SPEC3) & ~CORE_PWRSAVE_DLL),
host->ioaddr + CORE_VENDOR_SPEC3);
/* Select the default clock (free running MCLK) */ /* Select the default clock (free running MCLK) */
writel_relaxed(((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) writel_relaxed(((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
& ~CORE_HC_MCLK_SEL_MASK) & ~CORE_HC_MCLK_SEL_MASK)
@ -2667,6 +2748,13 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host,
(readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES) | (readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES) |
caps), host->ioaddr + CORE_VENDOR_SPEC_CAPABILITIES0); caps), host->ioaddr + CORE_VENDOR_SPEC_CAPABILITIES0);
} }
/*
* SDCC 5 controller with major version 1, minor version 0x34 and later
* with HS 400 mode support will use CM DLL instead of CDC LP 533 DLL.
*/
if ((major == 1) && (minor < 0x34))
msm_host->use_cdclp533 = true;
} }
static int sdhci_msm_probe(struct platform_device *pdev) static int sdhci_msm_probe(struct platform_device *pdev)