mmc: sdhci-msm: Factor out sdhci_msm_hc_select_mode
This factors out sdhci_msm_hc_select_mode to later use it during enhanced_strobe mode select. It also further breaks sdhci_msm_hc_select_mode into separate functions for configuring HS400 mode or other modes. Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org> Tested-by: Jeremy McNicoll <jeremymc@redhat.com> Acked-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
parent
73a85069f9
commit
b54aaa8a4f
@ -464,6 +464,119 @@ static int msm_init_cm_dll(struct sdhci_host *host)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void msm_hc_select_default(struct sdhci_host *host)
|
||||||
|
{
|
||||||
|
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||||
|
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
|
||||||
|
u32 config;
|
||||||
|
|
||||||
|
if (!msm_host->use_cdclp533) {
|
||||||
|
config = readl_relaxed(host->ioaddr +
|
||||||
|
CORE_VENDOR_SPEC3);
|
||||||
|
config &= ~CORE_PWRSAVE_DLL;
|
||||||
|
writel_relaxed(config, host->ioaddr +
|
||||||
|
CORE_VENDOR_SPEC3);
|
||||||
|
}
|
||||||
|
|
||||||
|
config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
|
||||||
|
config &= ~CORE_HC_MCLK_SEL_MASK;
|
||||||
|
config |= CORE_HC_MCLK_SEL_DFLT;
|
||||||
|
writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable HC_SELECT_IN to be able to use the UHS mode select
|
||||||
|
* configuration from Host Control2 register for all other
|
||||||
|
* modes.
|
||||||
|
* Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field
|
||||||
|
* in VENDOR_SPEC_FUNC
|
||||||
|
*/
|
||||||
|
config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
|
||||||
|
config &= ~CORE_HC_SELECT_IN_EN;
|
||||||
|
config &= ~CORE_HC_SELECT_IN_MASK;
|
||||||
|
writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure above writes impacting free running MCLK are completed
|
||||||
|
* before changing the clk_rate at GCC.
|
||||||
|
*/
|
||||||
|
wmb();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void msm_hc_select_hs400(struct sdhci_host *host)
|
||||||
|
{
|
||||||
|
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||||
|
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
|
||||||
|
u32 config, dll_lock;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Select the divided clock (free running MCLK/2) */
|
||||||
|
config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
|
||||||
|
config &= ~CORE_HC_MCLK_SEL_MASK;
|
||||||
|
config |= CORE_HC_MCLK_SEL_HS400;
|
||||||
|
|
||||||
|
writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
|
||||||
|
/*
|
||||||
|
* Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC
|
||||||
|
* register
|
||||||
|
*/
|
||||||
|
if (msm_host->tuning_done && !msm_host->calibration_done) {
|
||||||
|
config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
|
||||||
|
config |= CORE_HC_SELECT_IN_HS400;
|
||||||
|
config |= CORE_HC_SELECT_IN_EN;
|
||||||
|
writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
|
||||||
|
}
|
||||||
|
if (!msm_host->clk_rate && !msm_host->use_cdclp533) {
|
||||||
|
/*
|
||||||
|
* Poll on DLL_LOCK or DDR_DLL_LOCK bits in
|
||||||
|
* CORE_DLL_STATUS to be set. This should get set
|
||||||
|
* within 15 us at 200 MHz.
|
||||||
|
*/
|
||||||
|
rc = readl_relaxed_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);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Make sure above writes impacting free running MCLK are completed
|
||||||
|
* before changing the clk_rate at GCC.
|
||||||
|
*/
|
||||||
|
wmb();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sdhci_msm_hc_select_mode :- In general all timing modes are
|
||||||
|
* controlled via UHS mode select in Host Control2 register.
|
||||||
|
* eMMC specific HS200/HS400 doesn't have their respective modes
|
||||||
|
* defined here, hence we use these values.
|
||||||
|
*
|
||||||
|
* HS200 - SDR104 (Since they both are equivalent in functionality)
|
||||||
|
* HS400 - This involves multiple configurations
|
||||||
|
* Initially SDR104 - when tuning is required as HS200
|
||||||
|
* Then when switching to DDR @ 400MHz (HS400) we use
|
||||||
|
* the vendor specific HC_SELECT_IN to control the mode.
|
||||||
|
*
|
||||||
|
* In addition to controlling the modes we also need to select the
|
||||||
|
* correct input clock for DLL depending on the mode.
|
||||||
|
*
|
||||||
|
* HS400 - divided clock (free running MCLK/2)
|
||||||
|
* All other modes - default (free running MCLK)
|
||||||
|
*/
|
||||||
|
void sdhci_msm_hc_select_mode(struct sdhci_host *host)
|
||||||
|
{
|
||||||
|
struct mmc_ios ios = host->mmc->ios;
|
||||||
|
|
||||||
|
if (ios.timing == MMC_TIMING_MMC_HS400)
|
||||||
|
msm_hc_select_hs400(host);
|
||||||
|
else
|
||||||
|
msm_hc_select_default(host);
|
||||||
|
}
|
||||||
|
|
||||||
static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
|
static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
|
||||||
{
|
{
|
||||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||||
@ -894,7 +1007,6 @@ 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 = sdhci_pltfm_priv(pltfm_host);
|
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
|
||||||
struct mmc_ios curr_ios = host->mmc->ios;
|
struct mmc_ios curr_ios = host->mmc->ios;
|
||||||
u32 config, dll_lock;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (!clock) {
|
if (!clock) {
|
||||||
@ -913,93 +1025,8 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
|
|||||||
curr_ios.timing == MMC_TIMING_MMC_DDR52 ||
|
curr_ios.timing == MMC_TIMING_MMC_DDR52 ||
|
||||||
curr_ios.timing == MMC_TIMING_MMC_HS400)
|
curr_ios.timing == MMC_TIMING_MMC_HS400)
|
||||||
clock *= 2;
|
clock *= 2;
|
||||||
/*
|
|
||||||
* In general all timing modes are controlled via UHS mode select in
|
|
||||||
* Host Control2 register. eMMC specific HS200/HS400 doesn't have
|
|
||||||
* their respective modes defined here, hence we use these values.
|
|
||||||
*
|
|
||||||
* HS200 - SDR104 (Since they both are equivalent in functionality)
|
|
||||||
* HS400 - This involves multiple configurations
|
|
||||||
* Initially SDR104 - when tuning is required as HS200
|
|
||||||
* Then when switching to DDR @ 400MHz (HS400) we use
|
|
||||||
* the vendor specific HC_SELECT_IN to control the mode.
|
|
||||||
*
|
|
||||||
* In addition to controlling the modes we also need to select the
|
|
||||||
* correct input clock for DLL depending on the mode.
|
|
||||||
*
|
|
||||||
* HS400 - divided clock (free running MCLK/2)
|
|
||||||
* All other modes - default (free running MCLK)
|
|
||||||
*/
|
|
||||||
if (curr_ios.timing == MMC_TIMING_MMC_HS400) {
|
|
||||||
/* Select the divided clock (free running MCLK/2) */
|
|
||||||
config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
|
|
||||||
config &= ~CORE_HC_MCLK_SEL_MASK;
|
|
||||||
config |= CORE_HC_MCLK_SEL_HS400;
|
|
||||||
|
|
||||||
writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
|
sdhci_msm_hc_select_mode(host);
|
||||||
/*
|
|
||||||
* Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC
|
|
||||||
* register
|
|
||||||
*/
|
|
||||||
if (msm_host->tuning_done && !msm_host->calibration_done) {
|
|
||||||
/*
|
|
||||||
* Write 0x6 to HC_SELECT_IN and 1 to HC_SELECT_IN_EN
|
|
||||||
* field in VENDOR_SPEC_FUNC
|
|
||||||
*/
|
|
||||||
config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
|
|
||||||
config |= CORE_HC_SELECT_IN_HS400;
|
|
||||||
config |= CORE_HC_SELECT_IN_EN;
|
|
||||||
writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
|
|
||||||
}
|
|
||||||
if (!msm_host->clk_rate && !msm_host->use_cdclp533) {
|
|
||||||
/*
|
|
||||||
* Poll on DLL_LOCK or DDR_DLL_LOCK bits in
|
|
||||||
* CORE_DLL_STATUS to be set. This should get set
|
|
||||||
* within 15 us at 200 MHz.
|
|
||||||
*/
|
|
||||||
rc = readl_relaxed_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 {
|
|
||||||
if (!msm_host->use_cdclp533) {
|
|
||||||
config = readl_relaxed(host->ioaddr +
|
|
||||||
CORE_VENDOR_SPEC3);
|
|
||||||
config &= ~CORE_PWRSAVE_DLL;
|
|
||||||
writel_relaxed(config, host->ioaddr +
|
|
||||||
CORE_VENDOR_SPEC3);
|
|
||||||
}
|
|
||||||
|
|
||||||
config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
|
|
||||||
config &= ~CORE_HC_MCLK_SEL_MASK;
|
|
||||||
config |= CORE_HC_MCLK_SEL_DFLT;
|
|
||||||
writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Disable HC_SELECT_IN to be able to use the UHS mode select
|
|
||||||
* configuration from Host Control2 register for all other
|
|
||||||
* modes.
|
|
||||||
* Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field
|
|
||||||
* in VENDOR_SPEC_FUNC
|
|
||||||
*/
|
|
||||||
config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
|
|
||||||
config &= ~CORE_HC_SELECT_IN_EN;
|
|
||||||
config &= ~CORE_HC_SELECT_IN_MASK;
|
|
||||||
writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure above writes impacting free running MCLK are completed
|
|
||||||
* before changing the clk_rate at GCC.
|
|
||||||
*/
|
|
||||||
wmb();
|
|
||||||
|
|
||||||
rc = clk_set_rate(msm_host->clk, clock);
|
rc = clk_set_rate(msm_host->clk, clock);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user