On Sun, Jan 2, 2011 at 11:45 AM, Philip Rakity <prakity@xxxxxxxxxxx> wrote: > > mmc->caps MMC_CAP_1_8V_DDR is set by looking at cabability_1 > register if sd 3.0 controller. > > Support for dual data rate (DDR50) with 1_8V signalling added > with optional call back to enable external control of signalling > voltage. > > no support for 1.2V core voltage since SD 3.0 does not support > this. > > **** QUESTION **** > should this be part of regulator framework ? > > delay for signaling voltage to settle set to 5ms (per spec). > > this code does not change the voltage supplied to the card. > It assumes that this is correctly handled in the core/ layer. > > There is no requirement that the card voltage be at 1.8v > for DDR to work. This violates DDR specification for > SD Host Controller 3.0 since explicitly states card voltage > is 3.3v while signalling voltage is set to 1.8v. > > tested on mmp2 -- brownstone -- under linux-next. > > Note: this board design runs a fixed voltage to the card and > signaling voltage cannot be changed. > > Signed-off-by: Philip Rakity <prakity@xxxxxxxxxxx> > --- > drivers/mmc/host/sdhci.c | 53 ++++++++++++++++++++++++++++++++++++++++++--- > drivers/mmc/host/sdhci.h | 5 ++++ > 2 files changed, 54 insertions(+), 4 deletions(-) > > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c > index d5febe5..805f850 100644 > --- a/drivers/mmc/host/sdhci.c > +++ b/drivers/mmc/host/sdhci.c > @@ -84,6 +84,8 @@ static void sdhci_dumpregs(struct sdhci_host *host) > printk(KERN_DEBUG DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n", > sdhci_readw(host, SDHCI_COMMAND), > sdhci_readl(host, SDHCI_MAX_CURRENT)); > + printk(KERN_DEBUG DRIVER_NAME ": HostCtrl2:0x%08x\n", > + sdhci_readw(host, SDHCI_HOST_CONTROL_2)); > > if (host->flags & SDHCI_USE_ADMA) > printk(KERN_DEBUG DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", > @@ -986,6 +988,38 @@ static void sdhci_finish_command(struct sdhci_host *host) > host->cmd = NULL; > } > > +/* > + * Handle 1.8V signaling for DDR. No need to check for other > + * DDR values since driver supports ONLY 1_8V DDR. This is > + * set by the MMC_CAP_1_8V_DDR. 1_2V DDR is not supported. > + */ > +static void sdhci_set_ddr(struct sdhci_host *host, unsigned int ddr) > +{ > + u16 con; > + > + if (ddr == MMC_SDR_MODE) > + return; > + > + con = sdhci_readw(host, SDHCI_HOST_CONTROL_2); > + con |= SDCTRL_2_SDH_V18_EN; > + sdhci_writew(host, con, SDHCI_HOST_CONTROL_2); > + > + /* Change sigalling voltage and wait for it to be stable */ > + if (host->ops->set_signaling_voltage) > + host->ops->set_signaling_voltage(host, 18); > + else > + mdelay(5); In fact, have considered this method before, mdelay(5) in spin_lock_irqsave is terrible, since timer can not update system time, and android must die. > + > + /* > + * We can fail here but there is no higher level recovery > + * since the card is already past the switch to ddr > + */ > + con = sdhci_readw(host, SDHCI_HOST_CONTROL_2); > + con &= ~SDCTRL_2_UHS_MODE_MASK; > + con |= SDCTRL_2_UHS_MODE_SEL_DDR50; > + sdhci_writew(host, con, SDHCI_HOST_CONTROL_2); > +} > + > static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) > { > int div; > @@ -1180,6 +1214,7 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) > } > > sdhci_set_clock(host, ios->clock); > + sdhci_set_ddr(host, ios->ddr); > > if (ios->power_mode == MMC_POWER_OFF) > sdhci_set_power(host, -1); > @@ -1744,7 +1779,7 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host); > int sdhci_add_host(struct sdhci_host *host) > { > struct mmc_host *mmc; > - unsigned int caps, ocr_avail; > + unsigned int caps, caps_h, ocr_avail; > int ret; > > WARN_ON(host == NULL); > @@ -1767,8 +1802,19 @@ int sdhci_add_host(struct sdhci_host *host) > host->version); > } > > - caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps : > - sdhci_readl(host, SDHCI_CAPABILITIES); > + if (host->quirks & SDHCI_QUIRK_MISSING_CAPS) { > + caps = host->caps; > + caps_h = 0; > + } else { > + caps = sdhci_readl(host, SDHCI_CAPABILITIES); > + if (host->version >= SDHCI_SPEC_300) > + caps_h = sdhci_readl(host, SDHCI_CAPABILITIES_1); > + else > + caps_h = 0; > + } > + > + if (caps_h & SDHCI_CAN_DDR50) > + mmc->caps |= MMC_CAP_1_8V_DDR; > > if (host->quirks & SDHCI_QUIRK_FORCE_DMA) > host->flags |= SDHCI_USE_SDMA; > @@ -1905,7 +1951,6 @@ int sdhci_add_host(struct sdhci_host *host) > ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31; > if (caps & SDHCI_CAN_VDD_180) > ocr_avail |= MMC_VDD_165_195; > - > mmc->ocr_avail = ocr_avail; > mmc->ocr_avail_sdio = ocr_avail; > if (host->ocr_avail_sdio) > diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h > index 36f3861..d976e4f 100644 > --- a/drivers/mmc/host/sdhci.h > +++ b/drivers/mmc/host/sdhci.h > @@ -182,6 +182,9 @@ > #define SDHCI_CAN_64BIT 0x10000000 > > #define SDHCI_CAPABILITIES_1 0x44 > +#define SDHCI_CAN_SDR50 0x00000001 > +#define SDHCI_CAN_SDR104 0x00000002 > +#define SDHCI_CAN_DDR50 0x00000004 > > #define SDHCI_MAX_CURRENT 0x48 > > @@ -237,6 +240,8 @@ struct sdhci_ops { > void (*platform_send_init_74_clocks)(struct sdhci_host *host, > u8 power_mode); > unsigned int (*get_ro)(struct sdhci_host *host); > + unsigned int (*set_signaling_voltage)(struct sdhci_host *host, > + unsigned short voltage); > }; > > #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS > -- > 1.7.0.4 > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html