diff options
author | Masahiro Yamada | 2017-09-28 21:13:10 +0900 |
---|---|---|
committer | Jaehoon Chung | 2017-09-29 11:34:22 +0900 |
commit | 3d3108d459e6d034f20aab33b11f4d23537f0c27 (patch) | |
tree | 950362ffb82e2be54d8e486c82fb97dd1e847667 /drivers | |
parent | b016b585425b66ea53eef6b8600aff78a4205b9e (diff) |
mmc: sdhci-cadence: set timing mode register depending on frequency
The MMC framework in U-Boot does not support a systematic API for
timing switch like mmc_set_timing() in Linux.
U-Boot just provides a hook to change the clock frequency via
mmc_set_clock(). It is up to drivers if additional register
settings are needed.
This driver needs to set a correct timing mode into a register when
it migrates to a different speed mode. Only increasing clock frequency
could result in setup/hold timing violation.
The timing mode should be decided by checking MMC_TIMING_* like
drivers/mmc/host/sdhci-cadence.c in Linux, but "timing" is not
supported by U-Boot for now. Just use mmc->clock to decide the
timing mode.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/sdhci-cadence.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c index f83c1d72410..72d1c646a2b 100644 --- a/drivers/mmc/sdhci-cadence.c +++ b/drivers/mmc/sdhci-cadence.c @@ -23,6 +23,18 @@ #define SDHCI_CDNS_HRS04_WDATA_SHIFT 8 #define SDHCI_CDNS_HRS04_ADDR_SHIFT 0 +#define SDHCI_CDNS_HRS06 0x18 /* eMMC control */ +#define SDHCI_CDNS_HRS06_TUNE_UP BIT(15) +#define SDHCI_CDNS_HRS06_TUNE_SHIFT 8 +#define SDHCI_CDNS_HRS06_TUNE_MASK 0x3f +#define SDHCI_CDNS_HRS06_MODE_MASK 0x7 +#define SDHCI_CDNS_HRS06_MODE_SD 0x0 +#define SDHCI_CDNS_HRS06_MODE_MMC_SDR 0x2 +#define SDHCI_CDNS_HRS06_MODE_MMC_DDR 0x3 +#define SDHCI_CDNS_HRS06_MODE_MMC_HS200 0x4 +#define SDHCI_CDNS_HRS06_MODE_MMC_HS400 0x5 +#define SDHCI_CDNS_HRS06_MODE_MMC_HS400ES 0x6 + /* SRS - Slot Register Set (SDHCI-compatible) */ #define SDHCI_CDNS_SRS_BASE 0x200 @@ -111,6 +123,44 @@ static int sdhci_cdns_phy_init(struct sdhci_cdns_plat *plat, return 0; } +static void sdhci_cdns_set_control_reg(struct sdhci_host *host) +{ + struct mmc *mmc = host->mmc; + struct sdhci_cdns_plat *plat = dev_get_platdata(mmc->dev); + unsigned int clock = mmc->clock; + u32 mode, tmp; + + /* + * REVISIT: + * The mode should be decided by MMC_TIMING_* like Linux, but + * U-Boot does not support timing. Use the clock frequency instead. + */ + if (clock <= 26000000) + mode = SDHCI_CDNS_HRS06_MODE_SD; /* use this for Legacy */ + else if (clock <= 52000000) { + if (mmc->ddr_mode) + mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR; + else + mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR; + } else { + /* + * REVISIT: + * The IP supports HS200/HS400, revisit once U-Boot support it + */ + printf("unsupported frequency %d\n", clock); + return; + } + + tmp = readl(plat->hrs_addr + SDHCI_CDNS_HRS06); + tmp &= ~SDHCI_CDNS_HRS06_MODE_MASK; + tmp |= mode; + writel(tmp, plat->hrs_addr + SDHCI_CDNS_HRS06); +} + +static const struct sdhci_ops sdhci_cdns_ops = { + .set_control_reg = sdhci_cdns_set_control_reg, +}; + static int sdhci_cdns_bind(struct udevice *dev) { struct sdhci_cdns_plat *plat = dev_get_platdata(dev); @@ -137,6 +187,7 @@ static int sdhci_cdns_probe(struct udevice *dev) host->name = dev->name; host->ioaddr = plat->hrs_addr + SDHCI_CDNS_SRS_BASE; + host->ops = &sdhci_cdns_ops; host->quirks |= SDHCI_QUIRK_WAIT_SEND_CMD; ret = sdhci_cdns_phy_init(plat, gd->fdt_blob, dev_of_offset(dev)); |