]> rtime.felk.cvut.cz Git - hercules2020/nv-tegra/linux-4.4.git/commitdiff
mmc: Add single step mmc power up
authorPavan Kunapuli <pkunapuli@nvidia.com>
Mon, 11 May 2015 06:36:08 +0000 (12:06 +0530)
committerPavan Kunapuli <pkunapuli@nvidia.com>
Tue, 12 May 2015 06:46:00 +0000 (23:46 -0700)
Tegra sdmmc controllers can power up in single step. For such
controllers, added single step power up sequence.

Also, Tegra sdmmc controllers require controller clock to be
ON to access registers. Calling host->ops->set_clock to ensure
that host clock is turned ON before accessing any registers while
settings IOS.

Change-Id: I99b9e6a240b6771b87d590a210d7c5314086da4e
Signed-off-by: Pavan Kunapuli <pkunapuli@nvidia.com>
Reviewed-on: http://git-master/r/741545

drivers/mmc/core/core.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
include/linux/mmc/host.h

index 1156fa65b0dd96caba3f441cd38cce9eb7be1090..2c4ebf3f13d311bfecb19662a5c5daf476602dae 100644 (file)
@@ -2223,6 +2223,9 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
        host->ios.power_mode = MMC_POWER_UP;
        host->ios.bus_width = MMC_BUS_WIDTH_1;
        host->ios.timing = MMC_TIMING_LEGACY;
+       if (host->caps2 & MMC_CAP2_SINGLE_POWERON)
+               host->ios.clock = host->f_init;
+
        mmc_set_ios(host);
 
        /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
@@ -2239,6 +2242,11 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
         */
        mmc_delay(10);
 
+       if (host->caps2 & MMC_CAP2_SINGLE_POWERON) {
+               host->ios.power_mode = MMC_POWER_ON;
+               goto skip_power_on;
+       }
+
        host->ios.clock = host->f_init;
 
        host->ios.power_mode = MMC_POWER_ON;
@@ -2250,6 +2258,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
         */
        mmc_delay(10);
 
+skip_power_on:
        mmc_host_clk_release(host);
 }
 
index 6a18254a2ce78a2a634cf600fd3a6fb7cb0d8afd..ea222da39de4b19b3b2e686d72e8031ff063e910 100644 (file)
@@ -845,13 +845,13 @@ static void tegra_sdhci_clock_set_parent(struct sdhci_host *host,
 static void tegra_sdhci_get_clock_freq_for_mode(struct sdhci_host *sdhci,
                        unsigned int *clock)
 {
-       struct platform_device *pdev = to_platform_device(mmc_dev(sdhci->mmc));
-       const struct tegra_sdhci_platform_data *plat = pdev->dev.platform_data;
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
+       struct sdhci_tegra *tegra_host = pltfm_host->priv;
+       const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
        unsigned int ios_timing = sdhci->mmc->ios.timing;
        unsigned int index;
 
-       if (!(plat->is_fix_clock_freq) || !(pdev->dev.of_node)
-               || (ios_timing >= MMC_TIMINGS_MAX_MODES))
+       if (!(plat->is_fix_clock_freq) || (ios_timing >= MMC_TIMINGS_MAX_MODES))
                return;
 
        /*
@@ -2220,6 +2220,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
        /* disable access to boot partitions */
        host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC;
        host->mmc->caps2 |= MMC_CAP2_PACKED_CMD;
+       host->mmc->caps2 |= MMC_CAP2_SINGLE_POWERON;
        if (soc_data->nvquirks & NVQUIRK_EN_STROBE_SUPPORT)
                host->mmc->caps2 |= MMC_CAP2_EN_STROBE;
        if (plat->pwr_off_during_lp0)
index 92c997965957e2ab5b71e84d252cc68ffb3d72dd..0566613a99181e950e866bd0109385b1a4edb50d 100644 (file)
@@ -240,7 +240,7 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
 
 void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
-       u32 ctrl;
+       u16 ctrl;
        unsigned long timeout;
 
        sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
@@ -272,11 +272,11 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
         * need to re-configure them after each full reset
         */
        if ((mask & SDHCI_RESET_ALL) && host->version >= SDHCI_SPEC_400) {
-               ctrl = sdhci_readl(host, SDHCI_ACMD12_ERR);
+               ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
                ctrl |= SDHCI_HOST_VERSION_4_EN;
                if (host->quirks2 & SDHCI_QUIRK2_SUPPORT_64BIT_DMA)
                        ctrl |= SDHCI_ADDRESSING_64BIT_EN;
-               sdhci_writel(host, ctrl, SDHCI_ACMD12_ERR);
+               sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
        }
 }
 EXPORT_SYMBOL_GPL(sdhci_reset);
@@ -1431,13 +1431,14 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
        }
 
        timeout = jiffies;
-       if (!cmd->data && cmd->busy_timeout > 9000)
-               timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
-       else if ((cmd->opcode == MMC_SWITCH) && (((cmd->arg >> 16) &
+       if ((cmd->opcode == MMC_SWITCH) && (((cmd->arg >> 16) &
                EXT_CSD_SANITIZE_START) == EXT_CSD_SANITIZE_START))
                timeout += 100 * HZ;
+       else if (!cmd->data && cmd->busy_timeout > 9000)
+               timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
        else
                timeout += 10 * HZ;
+
        mod_timer(&host->timer, timeout);
 
        host->cmd = cmd;
@@ -2025,9 +2026,11 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
                sdhci_enable_preset_value(host, false);
 
-       if (!ios->clock || ios->clock != host->clock) {
+       if (ios->clock && ios->clock != host->clock) {
+               spin_unlock_irqrestore(&host->lock, flags);
                host->ops->set_clock(host, ios->clock);
                host->clock = ios->clock;
+               spin_lock_irqsave(&host->lock, flags);
 
                if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK &&
                    host->clock) {
@@ -2127,7 +2130,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                }
 
                /* Re-enable SD Clock */
-               host->ops->set_clock(host, host->clock);
+               clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+               clk |= SDHCI_CLOCK_CARD_EN;
+               sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
        } else
                sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
@@ -2141,6 +2146,11 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 
        mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
+
+       if (!ios->clock && ios->clock != host->clock) {
+               host->ops->set_clock(host, ios->clock);
+               host->clock = ios->clock;
+       }
 }
 
 static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
index d287f5294d91ab5ff5e1924e2a5b9703d9b35dc4..3936e1ec7826170e99e62df40ec0fbd2b88041d8 100644 (file)
@@ -341,6 +341,8 @@ struct mmc_host {
 #define MMC_CAP2_HS533         (1 << 19)       /* can support HS533*/
 #define MMC_CAP2_CQ            (1 << 20)       /* can support CQ*/
 #define MMC_CAP2_NO_SLEEP_CMD  (1 << 21)       /* cannot support sleep mode */
+#define MMC_CAP2_SINGLE_POWERON (1 << 22)      /* Host can power up in single step */
+
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
 
 #ifdef CONFIG_MMC_CLKGATE
@@ -637,4 +639,10 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
        return card->host->ios.timing == MMC_TIMING_MMC_HS400;
 }
 
+static inline bool mmc_card_hs533(struct mmc_card *card)
+{
+       return ((card->host->ios.timing == MMC_TIMING_MMC_HS400) &&
+               (card->host->caps2 & MMC_CAP2_HS533));
+}
+
 #endif /* LINUX_MMC_HOST_H */