[U-Boot] [PATCH] mmc: sdhci: Add the programmable clock mode support
Wenyou Yang
wenyou.yang at atmel.com
Mon Jun 20 03:58:46 CEST 2016
Add the programmable clock mode for the clock generator.
Signed-off-by: Wenyou Yang <wenyou.yang at atmel.com>
---
drivers/mmc/sdhci.c | 49 +++++++++++++++++++++++++++++++++++++++----------
include/sdhci.h | 15 +++++++++++++++
2 files changed, 54 insertions(+), 10 deletions(-)
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 5c71ab8..ee6d4a1 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -286,7 +286,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
{
struct sdhci_host *host = mmc->priv;
- unsigned int div, clk, timeout, reg;
+ unsigned int div, clk = 0, timeout, reg;
/* Wait max 20 ms */
timeout = 200;
@@ -310,14 +310,35 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
return 0;
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
- /* Version 3.00 divisors must be a multiple of 2. */
- if (mmc->cfg->f_max <= clock)
- div = 1;
- else {
- for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
- if ((mmc->cfg->f_max / div) <= clock)
+ /*
+ * Check if the Host Controller supports Programmable Clock
+ * Mode.
+ */
+ if (host->clk_mul) {
+ for (div = 1; div <= 1024; div++) {
+ if ((mmc->cfg->f_max * host->clk_mul / div)
+ <= clock)
break;
}
+
+ /*
+ * Set Programmable Clock Mode in the Clock
+ * Control register.
+ */
+ clk = SDHCI_PROG_CLOCK_MODE;
+ div--;
+ } else {
+ /* Version 3.00 divisors must be a multiple of 2. */
+ if (mmc->cfg->f_max <= clock) {
+ div = 1;
+ } else {
+ for (div = 2;
+ div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
+ if ((mmc->cfg->f_max / div) <= clock)
+ break;
+ }
+ }
+ div >>= 1;
}
} else {
/* Version 2.00 divisors must be a power of 2. */
@@ -325,13 +346,13 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
if ((mmc->cfg->f_max / div) <= clock)
break;
}
+ div >>= 1;
}
- div >>= 1;
if (host->set_clock)
host->set_clock(host->index, div);
- clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
+ clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
<< SDHCI_DIVIDER_HI_SHIFT;
clk |= SDHCI_CLOCK_INT_EN;
@@ -480,7 +501,7 @@ static const struct mmc_ops sdhci_ops = {
int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
{
- unsigned int caps;
+ unsigned int caps, caps_1;
host->cfg.name = host->name;
host->cfg.ops = &sdhci_ops;
@@ -546,6 +567,14 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
+ /*
+ * In case of Host Controller v3.00, find out whether clock
+ * multiplier is supported.
+ */
+ caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
+ host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >>
+ SDHCI_CLOCK_MUL_SHIFT;
+
sdhci_reset(host, SDHCI_RESET_ALL);
host->mmc = mmc_create(&host->cfg, host);
diff --git a/include/sdhci.h b/include/sdhci.h
index e0f6667..5abe0a2 100644
--- a/include/sdhci.h
+++ b/include/sdhci.h
@@ -97,6 +97,7 @@
#define SDHCI_DIV_MASK 0xFF
#define SDHCI_DIV_MASK_LEN 8
#define SDHCI_DIV_HI_MASK 0x300
+#define SDHCI_PROG_CLOCK_MODE 0x0020
#define SDHCI_CLOCK_CARD_EN 0x0004
#define SDHCI_CLOCK_INT_STABLE 0x0002
#define SDHCI_CLOCK_INT_EN 0x0001
@@ -166,6 +167,19 @@
#define SDHCI_CAN_64BIT 0x10000000
#define SDHCI_CAPABILITIES_1 0x44
+#define SDHCI_SUPPORT_SDR50 0x00000001
+#define SDHCI_SUPPORT_SDR104 0x00000002
+#define SDHCI_SUPPORT_DDR50 0x00000004
+#define SDHCI_DRIVER_TYPE_A 0x00000010
+#define SDHCI_DRIVER_TYPE_C 0x00000020
+#define SDHCI_DRIVER_TYPE_D 0x00000040
+#define SDHCI_RETUNING_TIMER_COUNT_MASK 0x00000F00
+#define SDHCI_RETUNING_TIMER_COUNT_SHIFT 8
+#define SDHCI_USE_SDR50_TUNING 0x00002000
+#define SDHCI_RETUNING_MODE_MASK 0x0000C000
+#define SDHCI_RETUNING_MODE_SHIFT 14
+#define SDHCI_CLOCK_MUL_MASK 0x00FF0000
+#define SDHCI_CLOCK_MUL_SHIFT 16
#define SDHCI_MAX_CURRENT 0x48
@@ -240,6 +254,7 @@ struct sdhci_host {
unsigned int quirks;
unsigned int host_caps;
unsigned int version;
+ unsigned int clk_mul; /* Clock Muliplier value */
unsigned int clock;
struct mmc *mmc;
const struct sdhci_ops *ops;
--
2.7.4
More information about the U-Boot
mailing list