Message ID | 1506600790-29419-1-git-send-email-yamada.masahiro@socionext.com |
---|---|
State | Accepted |
Commit | 3d3108d459e6d034f20aab33b11f4d23537f0c27 |
Headers | show |
Series | mmc: sdhci-cadence: set timing mode register depending on frequency | expand |
On 09/28/2017 09:13 PM, Masahiro Yamada wrote: > 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> Applied to u-boot-mmc. Thanks! Best Regards, Jaehoon Chung > --- > > This is a repost. > > I sent the same one before > http://patchwork.ozlabs.org/patch/764647/ > > I retracted it because I saw amazing framework improvements for MMC. > > 4 months have passed since then, but nothing happened. > > I do not wait any more. I am reposting it. > > > drivers/mmc/sdhci-cadence.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 51 insertions(+) > > diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c > index f83c1d7..72d1c64 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)); >
diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c index f83c1d7..72d1c64 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));
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> --- This is a repost. I sent the same one before http://patchwork.ozlabs.org/patch/764647/ I retracted it because I saw amazing framework improvements for MMC. 4 months have passed since then, but nothing happened. I do not wait any more. I am reposting it. drivers/mmc/sdhci-cadence.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+)