mmc: tegra: port to standard clock/reset APIs
authorStephen Warren <swarren@nvidia.com>
Fri, 5 Aug 2016 22:10:33 +0000 (16:10 -0600)
committerTom Warren <twarren@nvidia.com>
Mon, 15 Aug 2016 17:26:13 +0000 (10:26 -0700)
Tegra186 supports the new standard clock and reset APIs. Older Tegra SoCs
still use custom APIs. Enhance the Tegra MMC driver so that it can operate
with either set of APIs.

Signed-off-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Tom Warren <twarren@nvidia.com>
arch/arm/include/asm/arch-tegra/tegra_mmc.h
drivers/mmc/tegra_mmc.c

index 75e56c4ea7869e415b800954588f327312394e8f..07ef4c04c858a7021f925ded55f76414f85d228b 100644 (file)
@@ -9,6 +9,9 @@
 #ifndef __TEGRA_MMC_H_
 #define __TEGRA_MMC_H_
 
+#include <common.h>
+#include <clk.h>
+#include <reset.h>
 #include <fdtdec.h>
 #include <asm/gpio.h>
 
@@ -134,7 +137,10 @@ struct mmc_host {
        int id;                 /* device id/number, 0-3 */
        int enabled;            /* 1 to enable, 0 to disable */
        int width;              /* Bus Width, 1, 4 or 8 */
-#ifndef CONFIG_TEGRA186
+#ifdef CONFIG_TEGRA186
+       struct reset_ctl reset_ctl;
+       struct clk clk;
+#else
        enum periph_id mmc_id;  /* Peripheral ID: PERIPH_ID_... */
 #endif
        struct gpio_desc cd_gpio;       /* Change Detect GPIO */
index 023ba3c643d57c4d8b2c43f41e17f7c077375442..f0a39a63c641524a8b8798499e70fbe79794290b 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <bouncebuf.h>
 #include <common.h>
+#include <dm/device.h>
 #include <errno.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
 #include <asm/arch-tegra/tegra_mmc.h>
 #include <mmc.h>
 
+/*
+ * FIXME: TODO: This driver contains a number of ifdef CONFIG_TEGRA186 that
+ * should not be present. These are needed because newer Tegra SoCs support
+ * only the standard clock/reset APIs, whereas older Tegra SoCs support only
+ * a custom Tegra-specific API. ASAP the older Tegra SoCs' code should be
+ * fixed to implement the standard APIs, and all drivers converted to solely
+ * use the new standard APIs, with no ifdefs.
+ */
+
 DECLARE_GLOBAL_DATA_PTR;
 
 struct mmc_host mmc_host[CONFIG_SYS_MMC_MAX_DEVICE];
@@ -360,11 +370,14 @@ static void mmc_change_clock(struct mmc_host *host, uint clock)
         */
        if (clock == 0)
                goto out;
-#ifndef CONFIG_TEGRA186
+#ifdef CONFIG_TEGRA186
+       {
+               ulong rate = clk_set_rate(&host->clk, clock);
+               div = (rate + clock - 1) / clock;
+       }
+#else
        clock_adjust_periph_pll_div(host->mmc_id, CLOCK_ID_PERIPH, clock,
                                    &div);
-#else
-       div = (20000000 + clock - 1) / clock;
 #endif
        debug("div = %d\n", div);
 
@@ -539,6 +552,9 @@ static int do_mmc_init(int dev_index, bool removable)
 {
        struct mmc_host *host;
        struct mmc *mmc;
+#ifdef CONFIG_TEGRA186
+       int ret;
+#endif
 
        /* DT should have been read & host config filled in */
        host = &mmc_host[dev_index];
@@ -550,7 +566,21 @@ static int do_mmc_init(int dev_index, bool removable)
              gpio_get_number(&host->cd_gpio));
 
        host->clock = 0;
-#ifndef CONFIG_TEGRA186
+
+#ifdef CONFIG_TEGRA186
+       ret = reset_assert(&host->reset_ctl);
+       if (ret)
+               return ret;
+       ret = clk_enable(&host->clk);
+       if (ret)
+               return ret;
+       ret = clk_set_rate(&host->clk, 20000000);
+       if (IS_ERR_VALUE(ret))
+               return ret;
+       ret = reset_deassert(&host->reset_ctl);
+       if (ret)
+               return ret;
+#else
        clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000);
 #endif
 
@@ -577,11 +607,7 @@ static int do_mmc_init(int dev_index, bool removable)
         *  (actually 52MHz)
         */
        host->cfg.f_min = 375000;
-#ifndef CONFIG_TEGRA186
        host->cfg.f_max = 48000000;
-#else
-       host->cfg.f_max = 375000;
-#endif
 
        host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
 
@@ -613,7 +639,27 @@ static int mmc_get_config(const void *blob, int node, struct mmc_host *host,
                return -FDT_ERR_NOTFOUND;
        }
 
-#ifndef CONFIG_TEGRA186
+#ifdef CONFIG_TEGRA186
+       {
+               /*
+                * FIXME: This variable should go away when the MMC device
+                * actually is a udevice.
+                */
+               struct udevice dev;
+               int ret;
+               dev.of_offset = node;
+               ret = reset_get_by_name(&dev, "sdmmc", &host->reset_ctl);
+               if (ret) {
+                       debug("reset_get_by_index() failed: %d\n", ret);
+                       return ret;
+               }
+               ret = clk_get_by_name(&dev, "sdmmc", &host->clk);
+               if (ret) {
+                       debug("clk_get_by_index() failed: %d\n", ret);
+                       return ret;
+               }
+       }
+#else
        host->mmc_id = clock_decode_periph_id(blob, node);
        if (host->mmc_id == PERIPH_ID_NONE) {
                debug("%s: could not decode periph id\n", __func__);